fga/init.g0000644000371700037170000000134413275267465014161 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W init.g FGA package Christian Sievers ## ## The init file for the FGA package ## #Y 2003 - 2012 ## ReadPackage( "FGA", "lib/util.gd" ); ReadPackage( "FGA", "lib/Iterated.gd" ); ReadPackage( "FGA", "lib/Autom.gd" ); ReadPackage( "FGA", "lib/FreeGrps.gd" ); ReadPackage( "FGA", "lib/ReprAct.gd" ); ReadPackage( "FGA", "lib/Normal.gd" ); ReadPackage( "FGA", "lib/ExtAutom.gd" ); ReadPackage( "FGA", "lib/Hom.gd" ); ReadPackage( "FGA", "lib/AutGrp.gd" ); ReadPackage( "FGA", "lib/Intsect.gd" ); ReadPackage( "FGA", "lib/Whitehd.gd" ); ############################################################################# ## #E fga/read.g0000644000371700037170000000153413275267465014132 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W read.g FGA package Christian Sievers ## ## The read file for the FGA package ## #Y 2003 - 2012 ## ReadPackage( "FGA", "lib/util.gi" ); ReadPackage( "FGA", "lib/Iterated.gi" ); ReadPackage( "FGA", "lib/Autom.gi" ); ReadPackage( "FGA", "lib/FreeGrps.gi" ); ReadPackage( "FGA", "lib/ReprAct.gi" ); ReadPackage( "FGA", "lib/Normal.gi" ); ReadPackage( "FGA", "lib/Central.gi" ); ReadPackage( "FGA", "lib/Index.gi" ); ReadPackage( "FGA", "lib/ExtAutom.gi"); ReadPackage( "FGA", "lib/Hom.gi" ); ReadPackage( "FGA", "lib/AutGrp.gi" ); ReadPackage( "FGA", "lib/Intsect.gi" ); ReadPackage( "FGA", "lib/ReprActT.gi" ); ReadPackage( "FGA", "lib/Whitehd.gi" ); ############################################################################# ## #E fga/PackageInfo.g0000664000371700037170000001174513275267465015375 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W PackageInfo.g FGA package Christian Sievers ## ## The package info file for the FGA package ## #Y 2003 - 2018 ## SetPackageInfo( rec( PackageName := "FGA", Subtitle := "Free Group Algorithms", Version := "1.4.0", # dd/mm/yyyy Date := "23/03/2018", Persons := [ rec( LastName := "Sievers", FirstNames := "Christian", IsAuthor := true, IsMaintainer := true, Email := "c.sievers@tu-bs.de", # WWWHome := "", # PostalAddress := Concatenation( # [ "Christian Sievers\n", # "Fachbereich Mathematik und Informatik\n", # "Institut Computational Mathematics\n", # "Technische Universit\"at Braunschweig\n", # "Pockelsstr. 14\n", # "D-38106 Braunschweig,\n", # "Germany" ]), # Place := "Braunschweig", # Institution := "TU Braunschweig" ) ], Status := "accepted", CommunicatedBy := "Edmund Robertson (St. Andrews)", AcceptDate := "05/2005", ## For a central overview of all packages and a collection of all package ## archives it is necessary to have two files accessible which should be ## contained in each package: ## - A README file, containing a short abstract about the package ## content and installation instructions. ## - The file you are currently reading or editing! ## You must specify URLs for these two files, these allow to automate ## the updating of package information on the GAP Website, and inclusion ## and updating of the package in the GAP distribution. # PackageWWWHome := "http://www.icm.tu-bs.de/ag_algebra/software/FGA/", ArchiveFormats := ".tar.gz", ArchiveURL := Concatenation( ~.PackageWWWHome, "FGA-", ~.Version ), README_URL := Concatenation( ~.PackageWWWHome, "README" ), PackageInfoURL := Concatenation( ~.PackageWWWHome, "PackageInfo.g" ), SourceRepository := rec( Type := "git", URL := "https://github.com/chsievers/fga" ), IssueTrackerURL := Concatenation( ~.SourceRepository.URL, "/issues" ), ## Here you must provide a short abstract explaining the package content ## in HTML format (used on the package overview Web page) and an URL ## for a Webpage with more detailed information about the package ## (not more than a few lines, less is ok): ## Please, use 'GAP' and ## 'MyPKG' for specifing package names. ## AbstractHTML := "The FGA package installs methods for \ computations with finitely generated subgroups of free groups and \ provides a presentation for their automorphism groups.", ## On the GAP Website there is an online version of all manuals in the ## GAP distribution. To handle the documentation of a package it is ## necessary to have: ## - an archive containing the package documentation (in at least one ## of HTML or PDF-format, preferably both formats) ## - the start file of the HTML documentation (if provided), *relative to ## package root* ## - the PDF-file (if provided) *relative to the package root* ## For links to other package manuals or the GAP manuals one can assume ## relative paths as in a standard GAP installation. ## Also, provide the information about autoloadability of the documentation. ## ## Please, don't include unnecessary files (.log, .aux, .dvi, .ps, ...) in ## the provided documentation archive. ## # in case of several help books give a list of such records here: PackageDoc := rec( # use same as in GAP BookName := "FGA", # format/extension can be one of .zoo, .tar.gz, .tar.bz2, -win.zip # Archive := "", ArchiveURLSubset := ["doc", "htm"], HTMLStart := "htm/chapters.htm", PDFFile := "doc/manual.pdf", # the path to the .six file used by GAP's help system SixFile := "doc/manual.six", # a longer title of the book, this together with the book name should # fit on a single text line (appears with the '?books' command in GAP) LongTitle := "Free Group Algorithms", # Should this help book be autoloaded when GAP starts up? This should # usually be 'true', otherwise say 'false'. Autoload := true ), ## Are there restrictions on the operating system for this package? Or does ## the package need other packages to be available? Dependencies := rec( GAP := ">=4.8", NeededOtherPackages := [], SuggestedOtherPackages := [], ExternalConditions := [] ), AvailabilityTest := ReturnTrue, #BannerString := "" Autoload := true, ## *Optional*, but recommended: path relative to package root to a file which ## contains as many tests of the package functionality as sensible. TestFile := "tst/testall.g", Keywords := ["free groups", "inverse finite automata", "basic coset enumeration", "finite presentation of the automorphism group of a free group"] )); ############################################################################# ## #E fga/COPYING0000644000371700037170000004370613275267465014111 0ustar gap-jenkinsgap-jenkinsThe FGA package is free software; you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Version 2 of the GNU General Public License follows. ===================================================================== GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 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. fga/README0000664000371700037170000000227413275267465013733 0ustar gap-jenkinsgap-jenkins FGA Free Group Algorithms A GAP 4 package Contents: --------- The FGA package provides methods for computations with finitely generated subgroups of free groups. It allows you to (constructively) test membership and conjugacy, and to compute free generators, the rank, the index, normalizers, centralizers, and intersections where the groups involved are finitely generated subgroups of free groups. In addition, it provides generators and a finite presentation for the automorphism group of a finitely generated free group and allows to write any such automorphism as word in these generators. Requirements: ------------- FGA is written for GAP version 4.8 or later. It does not use external programs and does not depend on system specifics. License: -------- The FGA package is free software and can be redistributed and/or modified under the terms of the GNU General Public License. For details see the file COPYING. Installation: ------------- The installation follows standard GAP rules. So the normal way to install is to unpack the archive in the `pkg' directory, which will create an `fga' subdirectory. Enjoy! fga/lib/Normal.gi0000644000371700037170000000611513275267465015366 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Normal.gi FGA package Christian Sievers ## ## Method installations for normalizers in free groups ## #Y 2003 - 2012 ## ############################################################################# ## #M NormalizerInWholeGroup( ) ## ## returns the normalizer of in the group of the whole family ## InstallMethod( NormalizerInWholeGroup, [ CanComputeWithInverseAutomaton ], function(G) local found, A, reducedPos, states, s, u, ur, i, gens, redgenwords, fam, interesting, conjinvLetterRep, N; if IsTrivial( G ) then N := Group( FreeGeneratorsOfWholeGroup( G ) ); SetIsWholeFamily( N, true ); return N; fi; found := false; A := FreeGroupAutomaton(G); fam := ElementsFamily(FamilyObj(G)); gens := ShallowCopy(FreeGeneratorsOfGroup(G)); redgenwords := List(gens, LetterRepAssocWord); reducedPos := FGA_reducedPos(A); conjinvLetterRep := redgenwords[1]{[1..reducedPos-1]}; redgenwords := List(redgenwords, w -> w{[reducedPos .. Length(w)-reducedPos+1]}); states := FGA_States(FreeGroupAutomaton(G)); interesting := ReturnTrue; for i in [reducedPos+1 .. Length(states)] do s := states[i]; u := FGA_repr(s); ur := u{[reducedPos..Length(u)]}; if interesting(ur) and ForAll(redgenwords,w->FGA_Check(s,w)) then # generator found if found then # this was not the first extra generator # Print("inserting\n"); else # Print("inserting first\n"); A := FGA_FromGeneratorsLetterRep(redgenwords, G); interesting := w -> not FGA_Check(A!.initial,w); found := true; fi; FGA_AutomInsertGeneratorLetterRep(A, ur); # Add(gens, AssocWordByLetterRep(fam, u)); fi; od; if found then s := FGA_newstate(); FGA_coincidence(Iterated(conjinvLetterRep, FGA_define, s ), A!.initial ); A!.initial := FGA_find(s); A!.terminal := A!.initial; MakeImmutable(A); N := AsGroup(A); else N := G; fi; return N; end ); ############################################################################# ## #M NormalizerOp( , ) ## InstallMethod( NormalizerOp, "for a subgroup of a free group", IsIdenticalObj, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton ], function(F,G) return Intersection( F, NormalizerInWholeGroup( G ) ); end ); ############################################################################# ## #M NormalizerOp( , ) ## InstallMethod( NormalizerOp, "for an element in a free group", IsCollsElms, [ IsFreeGroup, IsElementOfFreeGroup ], CentralizerOp ); ############################################################################# ## #E fga/lib/Normal.gd0000644000371700037170000000113213275267465015353 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Normal.gd FGA package Christian Sievers ## ## The declaration file for the computation of normalizers in free groups ## #Y 2003 - 2012 ## ############################################################################# ## #A NormalizerInWholeGroup( ) ## ## returns the normalizer of in the group of the whole family ## DeclareAttribute( "NormalizerInWholeGroup", IsFreeGroup ); ############################################################################# ## #E fga/lib/ExtAutom.gi0000644000371700037170000001606413275267465015710 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W ExtAutom.gi FGA package Christian Sievers ## ## Methods to create and compute with extended inverse automata ## #Y 2003 - 2016 ## InstallValue( FGA_FreeGroupForGenerators, FreeGroup(infinity) ); InstallValue( FGA_One, One(FGA_FreeGroupForGenerators) ); InstallGlobalFunction( FGA_newstateX, function() return (rec (delta:=[], deltainv:=[], sndsig:=[], sndsiginv:=[])); end ); InstallGlobalFunction( FGA_connectposX, function(s1, s2, g, sndsig, sndsiginv) s1.delta[g] := s2; s2.deltainv[g] := s1; s1.sndsig[g] := sndsig; s2.sndsiginv[g] := sndsiginv; end ); InstallGlobalFunction( FGA_connectX, function(s1, s2, g, sndsig) if g>0 then FGA_connectposX(s1, s2, g, sndsig, sndsig^-1); else FGA_connectposX(s2, s1, -g, sndsig^-1, sndsig); fi; end ); InstallGlobalFunction( FGA_defineX, function(state, gen) local nstate; nstate := FGA_newstateX(); FGA_connectX(state, nstate, gen, FGA_One); # nstate.W := state.W * gen return nstate; end ); # active InstallGlobalFunction( FGA_findX, function(s) local sndsig; sndsig := FGA_One; while IsBound(s.isnow) do sndsig := sndsig * s.sndcoinc; s := s.isnow; od; return rec(state:=s, sndcoinc:=sndsig); # todo: path compression end ); InstallGlobalFunction( FGA_mergeX, function(s1, A, s2, B, Q) local s, C; s1 := FGA_findX(s1); s2 := FGA_findX(s2); if IsNotIdenticalObj(s1.state,s2.state) then if IsBound(s2.state.isinitial) then # don't mess with the initial state s := s1; s1 := s2; s2 := s; C := A; A := B; B := C; fi; s2.state.isnow := s1.state; s2.state.sndcoinc := (B*s2.sndcoinc)^-1*A*s1.sndcoinc; Add(Q,s2.state); fi; end ); InstallGlobalFunction( FGA_coincidenceX, function(s1, A, s2, B) local Q, s, g, s0, s01, delta, deltainv; Q := []; FGA_mergeX(s1, A, s2, B, Q); for s in Q do delta := ShallowCopy(s.delta); for g in BoundPositions(delta) do Unbind(delta[g].deltainv[g]); od; deltainv := ShallowCopy(s.deltainv); for g in BoundPositions(deltainv) do Unbind(deltainv[g].delta[g]); od; for g in BoundPositions(delta) do s0 := FGA_findX(s); s01 := FGA_findX(delta[g]); if IsBound(s0.state.delta[g]) then FGA_mergeX(s01.state, s.sndsig[g]*s01.sndcoinc, s0.state.delta[g], s0.sndcoinc*s0.state.sndsig[g], Q); elif IsBound(s01.state.deltainv[g]) then FGA_mergeX(s0.state, s.sndsig[g]^-1*s0.sndcoinc, s01.state.deltainv[g], s01.sndcoinc*s01.state.sndsiginv[g], Q); else FGA_connectX(s0.state, s01.state, g, s0.sndcoinc^-1*s.sndsig[g]*s01.sndcoinc); fi; od; for g in BoundPositions(deltainv) do s0 := FGA_findX(s); s01 := FGA_findX(deltainv[g]); if IsBound(s0.state.deltainv[g]) then FGA_mergeX(s01.state, s.sndsiginv[g]*s01.sndcoinc, s0.state.deltainv[g], s0.sndcoinc*s0.state.sndsiginv[g], Q); elif IsBound(s01.state.delta[g]) then FGA_mergeX(s0.state, s.sndsiginv[g]^-1*s0.sndcoinc, s01.state.delta[g], s01.sndcoinc*s01.state.sndsig[g], Q); else FGA_connectX(s01.state, s0.state, g, s01.sndcoinc^-1*s.sndsiginv[g]^-1*s0.sndcoinc); fi; od; od; end ); InstallGlobalFunction( FGA_atfX, function(l, lx, p) if IsBound(l[p]) then return rec(state:=l[p], sndsig:=lx[p]); else return fail; fi; end ); InstallGlobalFunction( FGA_deltaX, function(state, gen) if gen>0 then return FGA_atfX(state.delta, state.sndsig, gen); else return FGA_atfX(state.deltainv, state.sndsiginv, -gen); fi; end ); InstallGlobalFunction( FGA_stepX, function(r, gen) local res; res := FGA_deltaX(r.state, gen); if res <> fail then res.sndsig := r.sndsig * res.sndsig; fi; return res; end ); InstallGlobalFunction( FGA_deltasX, function(state, genlist) return IteratedF(genlist, FGA_stepX, rec(state:=state, sndsig:=FGA_One)); end ); InstallGlobalFunction( FGA_traceX, function(s,w) local i, s1; s := rec(state := s, sndsig := FGA_One); s1 := s; i := 1; while i <= Length(w) and s1 <> fail do s := s1; s1 := FGA_stepX(s, w[i]); i := i+1; od; if s1 = fail then return rec(state:=s.state, index:=i-1, sndsig:=s.sndsig); else return rec(state:=s1.state, index:=i, sndsig:=s1.sndsig); fi; end ); InstallGlobalFunction( FGA_backtraceX, function(s,w,j) local i, s1; s := rec(state:=s, sndsig := FGA_One); s1 := s; i := Length(w); while i >= j and s1 <> fail do s := s1; s1 := FGA_stepX(s, -w[i]); i := i-1; od; if s1 = fail then return rec(state:=s.state, index:=i+1, sndsig:=s.sndsig ); else return rec(state:=s1.state, index:=i, sndsig:=s1.sndsig); fi; end ); InstallGlobalFunction( FGA_insertgeneratorX, function(s, g, sndgen) local i, t, bt, s1, s2; t := FGA_traceX(s, g); bt := FGA_backtraceX(s, g, t.index); s1 := t.state; s2 := bt.state; if t.index > bt.index then # trace complete FGA_coincidenceX(s1, sndgen^-1*t.sndsig, s2, bt.sndsig); else if IsIdenticalObj(s1, s2) then while g[t.index] = -g[bt.index] do s1 := FGA_defineX(s1, g[t.index]); t.index := t.index+1; bt.index := bt.index - 1; od; s2 := s1; fi; for i in [t.index .. bt.index-1] do s1 := FGA_defineX(s1, g[i]); od; FGA_connectX(s1, s2, g[bt.index], t.sndsig^-1*sndgen*bt.sndsig); fi; return FGA_find(s); end ); InstallGlobalFunction( FGA_fromgeneratorsX, function(gens) local gen, i, autom; i := 1; autom := FGA_newstateX(); autom.isinitial := true; for gen in gens do autom := FGA_insertgeneratorX(autom, gen, FGA_FreeGroupForGenerators.(i) ); i := i+1; od; return autom; end ); InstallGlobalFunction( FGA_FromGroupWithGeneratorsX, function( G ) return FGA_fromgeneratorsX( List ( GeneratorsOfGroup ( G ), LetterRepAssocWord )); end ); InstallGlobalFunction( FGA_AsWordLetterRepInGenerators, function( w, A) local res; res := FGA_deltasX( A, w ); if res = fail or IsNotIdenticalObj( res.state, A ) then return fail; else return LetterRepAssocWord( res.sndsig ); fi; end ); ############################################################################# ## #E fga/lib/Autom.gd0000664000371700037170000000331613275267465015220 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Autom.gd FGA package Christian Sievers ## ## Declarations for methods to create and compute with inverse automata ## #Y 2003 - 2018 ## DeclareCategory( "IsInvAutomatonCategory", IsObject); DeclareOperation( "TrivialInvAutomaton", [ IsFreeGroup ]); DeclareOperation( "InvAutomatonInsertGenerator", [ IsInvAutomatonCategory and IsMutable, IsElementOfFreeGroup ] ); DeclareGlobalFunction( "FGA_newstate" ); DeclareGlobalFunction( "FGA_connectpos" ); DeclareGlobalFunction( "FGA_connect" ); DeclareGlobalFunction( "FGA_define" ); DeclareGlobalFunction( "FGA_find" ); DeclareGlobalFunction( "FGA_merge" ); DeclareGlobalFunction( "FGA_coincidence" ); DeclareGlobalFunction( "FGA_delta" ); DeclareGlobalFunction( "FGA_deltas" ); DeclareGlobalFunction( "FGA_TmpState" ); DeclareGlobalFunction( "FGA_trace" ); DeclareGlobalFunction( "FGA_backtrace" ); DeclareGlobalFunction( "FGA_InsertGenerator" ); DeclareGlobalFunction( "FGA_AutomInsertGeneratorLetterRep" ); DeclareGlobalFunction( "FGA_InsertGeneratorLetterRep" ); DeclareGlobalFunction( "FGA_FromGroupWithGenerators" ); DeclareGlobalFunction( "FGA_FromGeneratorsLetterRep"); DeclareGlobalFunction( "FGA_Check" ); DeclareGlobalFunction( "FGA_FindGeneratorsAndStates" ); DeclareGlobalFunction( "FGA_repr" ); DeclareGlobalFunction( "FGA_initial" ); DeclareGlobalFunction( "FGA_reducedPos" ); DeclareGlobalFunction( "FGA_Index" ); DeclareGlobalFunction( "FGA_AsWordLetterRepInFreeGenerators" ); DeclareGlobalFunction( "FGA_States" ); DeclareGlobalFunction( "FGA_GeneratorsLetterRep" ); ############################################################################# ## #E fga/lib/Central.gi0000644000371700037170000000414013275267465015522 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Central.gi FGA package Christian Sievers ## ## Method installations for centralizers in free groups ## #Y 2003 - 2012 ## ############################################################################# ## #M CentralizersOp( , ) ## InstallMethod( CentralizerOp, "for an element in a free group", IsCollsElms, [ IsFreeGroup, IsElementOfFreeGroup ], function(G,g) local i, l, len, div, w, f, p, pp, c; if g=One(G) then return G; fi; w := LetterRepAssocWord(g); i := 1; l := Length(w); while w[i] = -w[l] do i := i+1; l := l-1; od; len := l-i+1; pp := PrimePowersInt(len); f := 1; while f 0 and w{[i..i+len-(len/div)-1]} = w{[i+len/div..i+len-1]} do len := len/div; p := p-1; od; f := f+2; od; # return Group(AssocWordByLetterRep(FamilyObj(g), w{[i..i+len-1]})^ # AssocWordByLetterRep(FamilyObj(g), w{[l+1..Length(w)]}) ); c := FindPowLetterRep(G, w{[1..i-1]}, w{[i..i+len-1]}, w{[l+1..Length(w)]} ); if c = fail then return TrivialSubgroup(G); else return Group(c); fi; end ); ############################################################################# ## #M CentralizerOp( , ) ## InstallMethod( CentralizerOp, "for a subgroup of a free group", IsIdenticalObj, [ IsFreeGroup, IsFreeGroup ], function(F,G) local r; r := RankOfFreeGroup(G); if r >= 2 then return TrivialSubgroup(F); elif r = 1 then return Centralizer(F, FreeGeneratorsOfGroup(G)[1]); else # (r = 0) return F; fi; end ); ############################################################################# ## #E fga/lib/AutGrp.gi0000644000371700037170000003263713275267465015350 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W AutGrp.gi FGA package Christian Sievers ## ## Methods for automorphism groups of free groups ## #Y 2003 - 2012 ## ############################################################################# ## #M AutomorphismGroup( ) ## InstallMethod( AutomorphismGroup, "for free groups", [ CanComputeWithInverseAutomaton ], function( G ) local n, aut; n := RankOfFreeGroup( G ); if n = 0 then aut := AsGroup( [ IdentityMapping ( G ) ] ); elif n = 1 then aut := Group( FreeGroupAutomorphismsGeneratorO( G ) ); SetSize( aut, 2 ); elif n = 2 then aut := Group( FreeGroupAutomorphismsGeneratorO( G ), FreeGroupAutomorphismsGeneratorP( G ), FreeGroupAutomorphismsGeneratorU( G ) ); elif n = 3 then aut := Group( FreeGroupAutomorphismsGeneratorS( G ), FreeGroupAutomorphismsGeneratorT( G ), FreeGroupAutomorphismsGeneratorU( G ) ); elif IsEvenInt( n ) then aut := Group( FreeGroupAutomorphismsGeneratorQ( G ), FreeGroupAutomorphismsGeneratorR( G ) ); else # n > 3, odd aut := Group( FreeGroupAutomorphismsGeneratorS( G ), FreeGroupAutomorphismsGeneratorR( G ) ); fi; SetIsFinite( aut, n <= 1 ); SetFilterObj( aut, IsAutomorphismGroupOfFreeGroup ); return aut; end ); ############################################################################# ## #M \in( , ) ## ## tests whether is in . ## ## Code contributed by Max Horn. InstallMethod( \in, "for automorphism groups of free groups", [ IsGroupGeneralMapping, IsAutomorphismGroupOfFreeGroup ], function( hom, aut ) local G; G := AutomorphismDomain( aut ); return Source( hom ) = G and Range( hom ) = G and IsBijective( hom ); end ); ############################################################################# ## #M IsomorphismFpGroup( ) ## ## returns an isomorphism from an automorphism group of a free group ## to a finitely presented group. ## ## The presentation follows Bernhard Neumann (see ../doc/manual.bib) ## Numbers in the comments refer to the equation numbers in that paper. ## InstallMethod( IsomorphismFpGroup, "for automorphism groups of free groups", [ IsAutomorphismGroupOfFreeGroup ], function( aut ) local n, f, fp, O, P, U, S, T, Q, R, rels, moreRels, o, p, u, s, t, q, r, iso, isoinv; n := RankOfFreeGroup( AutomorphismDomain ( aut )); if n = 0 then fp := FreeGroup( 0 ); iso := aut -> One( fp ); elif n = 1 then f := FreeGroup( "O" ); O := f.1; rels := [ O^2 ]; # 6a fp := f / rels; o := fp.1; iso := aut -> o ^ (Order(aut) - 1); elif n = 2 then f := FreeGroup( "O", "P", "U" ); O := f.1; P := f.2; U := f.3; rels := [ P^2 # 5a , O^2 # 6a , (O*P)^4 # 8a , Comm( U, O*U*O ) # 7e , (P*O*P*U)^2 # 7i , (U*P*O)^3 # 8b ]; fp := f / rels; o := fp.1; p := fp.2; u := fp.3; iso := FGA_CurryAutToPQOU( p, p, o, u); # Q=P elif n = 3 then f := FreeGroup( "S", "T", "U" ); S := f.1; T := f.2; U := f.3; rels := [ (S^5*T^-1)^2 # 19a , T^-1*S*T^2*S^8*T^-1*S*T^2*S^-4 # 19b , (S^4*T^-1*S*T^-1)^2 # 19c , T^4 # 19d , Comm( U, S^2*T^-1*S*T^-1*S^2 ) # 19e , Comm( U, S^-2*T^-1*S*T^-1*U*S^-2*T^-1*S*T^-1) # 19f # wrong: Comm( U, S^2*T^-1*S*T*S*T^-1*U*T*S^-1*T^-1*S^-1*T*S^2 ) # 19g , Comm( U, S^-2*T^-1*S*T*S*T^-1*U* T*S^-1*T^-1*S^-1*T*S^2 ) # 19g corrected , Comm( U, T^-1*S*T^2*U*T^-1*S*T^2 ) # 19h , S^-2*T^-1*S*T^2*S^2*U*S^2*T^-1*S*T^2*S^2* U*S^-2*U*S^2*U^-1*S^-2*U^-1 # 19i , (S^-2*T^-1*S*T*U)^2 # 19j , (U*T)^3 # 19k ]; fp := f / rels; s := fp.1; t := fp.2; u := fp.3; iso := FGA_CurryAutToPQOU( t*s^3*(s*t^-1)^2 # 16c , s^4 # 16a , s^3*(s*t^-1)^2 # 16b , u ); elif IsEvenInt(n) then f := FreeGroup( "Q", "R" ); Q := f.1; R := f.2; rels := [ (R^3*(Q*R^3)^(n-1))^2 # 22a , (Q*R^3)^(2*(n-1)) # 22d , Q^n # 22e , Comm( (Q*R^3)^(n-1), Q^-1*R^3*(Q*R^3)^(n-1)*Q ) # 22f , Comm( Q^-2*R^4*Q^2*R^-3, Q*R^-3*Q^-1*R^-3*Q ) # 22h , Comm( R^4, (Q*R^3)^(n-1) ) # 22j , Comm( R^4, Q^-2*R^4*Q^2 ) # 22k , Comm( Q^-2*R^4*Q^2*R^-3, (Q*R^3)^(n-1)*Q^-2*R^4*Q^2*R^-3*(Q*R^3)^(n-1) ) # 22l , Comm( Q^-2*R^4*Q^2*R^-3, R^-3*Q^-1*Q^-2*R^4*Q^2*R^-3*Q*R^3 ) # 22m , Comm( Q^-2*R^4*Q^2*R^-3, R^-3*Q^-1*R^-3*(Q*R^3)^n*Q^-2*R^4* Q^2*R^-3*(Q*R^3)^-n*R^3*Q*R^3 ) # 22n , (Q*R^3)^-n*Q^-2*R^4*Q^2*R^-3*(Q*R^3)^n* Q^-3*R^4*Q^2*R^-3*Q^-1*R^4*Q^2*R^-3* Q^-1*R^3*Q^-2*R^-4*Q^3*R^3*Q^-2*R^-4*Q^2 # 22o , (R^3*(Q*R^3)^(n-1)*Q^-2*R^4*Q^2)^2 # 22p , R^12 # 22q ]; # finally the relations 22c: moreRels := List( [ 2 .. n/2 ], i -> Comm( R^3*(Q*R^3)^(n-1), Q^-i*R^3*(Q*R^3)^(n-1)*Q^i ) ); fp := f / Concatenation(rels, moreRels); q := fp.1; r := fp.2; iso := FGA_CurryAutToPQOU( r^3*(q*r^3)^(n-1) # 21b , q , (q*r^3)^(n-1) # 21a , q^-2*r^4*q^2*r^-3 # 21c ); else # n > 3, odd f := FreeGroup( "S", "R" ); S := f.1; R := f.2; rels := [ (R^3*S^n*(S*R^-3)^(n-1))^2 # 25a , (S^(n+1)*R^3*S^n*(S*R^-3)^(n-1))^(n-1)* S^((-n)*(n-1)) # 25b , ((S^n)*(S*R^-3)^(n-1))^2 # 25d , Comm( S^n*(S*R^-3)^(n-1), S^-(n+1)*R^3*S^n* (S*R^-3)^(n-1)*S^(n+1) ) # 25e , Comm( S^-2*R^4*S^2*R^3, S*R^-3*S^(n-1)*R^-3*S ) # 25f , Comm( R^4, S^n*(S*R^-3)^(n-1) ) # 25g , Comm( R^4, S^-2*R^4*S^2 ) # 25h , Comm( S^-2*R^4*S^2*R^-3, S^n*(S*R^-3)^(n-1)*S^-2*R^4*S^2* R^-3*S^n*(S*R^-3)^(n-1) ) # 25i , Comm( S^-2*R^4*S^2*R^-3, R^-3*S^-(n+1)*S^-2*R^4*S^2* R^-3*S^(n+1)*R^3 ) # 25j # wrong: , Comm( S^-2*R^4*S^2*R^-3, # R^-3*S^-1*R^-3*S*R^3*S^n* # (S*R^-3)^(n-1)*S^-2*R^4*S^2*R^3* # (S*R^-3)^(n-1)*S^n*R^-3*S^-1* # R^3*S*R^3 ) # 25k , Comm( S^-2*R^4*S^2*R^-3, R^-3*S^-1*R^-3*S*R^3*S^n* (S*R^-3)^(n-1)*S^-2*R^4*S^2*R^-3* (S*R^-3)^(n-1)*S^n*R^-3*S^-1* R^3*S*R^3 ) # 25k corrected , R^3*(S*R^-3)^(n-1)*S^-3*R^4*S^2*R^-3*S* R^3*(S*R^-3)^(n-1)*S^(n-3)*R^4*S^2*R^-3* S^(n-1)*R^4*S^2*R^-3*S^(n-1)*R^3*S^-2* R^-4*S^(n+3)*R^3*S^-2*R^-4*S^2 # 25l , (R^3*(S*R^-3)^(n-1)*S^(n-2)*R^4*S^2)^2 # 25m , R^12 # 22q ] ; # and finally the relations 25c: moreRels := List( [ 2 .. (n-1)/2 ], i -> Comm( R^3*S^n*(S*R^-3)^(n-1), S^(-i*(n+1))*R^3*S^n* (S*R^-3)^(n-1)*S^(i*(n+1)) ) ); fp := f / Concatenation( rels, moreRels ); s := fp.1; r := fp.2; iso := FGA_CurryAutToPQOU( r^3*s^n*(s*r^-3)^(n-1) # 24c , s^(n+1) # 24a , s^n*(s*r^-3)^(n-1) # 24b , s^(-2*(n+1))*r^4*s^(2*(n+1))*r^-3 # 24d ); fi; isoinv := GroupHomomorphismByImagesNC( fp, aut, GeneratorsOfGroup( fp ), GeneratorsOfGroup( aut ) ); return GroupHomomorphismByFunction( aut, fp, iso, x -> x ^ isoinv ); end ); ############################################################################# ## #F FreeGroupEndomorphismByImages( , ) ## ## returns the endomorphism of that maps the generators of ## to . ## InstallGlobalFunction( FreeGroupEndomorphismByImages, function(g,l) return GroupHomomorphismByImages(g,g,FreeGeneratorsOfGroup(g),l); end ); ############################################################################# ## #F FreeGroupAutomorphismsGeneratorO( ) #F FreeGroupAutomorphismsGeneratorP( ) #F FreeGroupAutomorphismsGeneratorU( ) #F FreeGroupAutomorphismsGeneratorS( ) #F FreeGroupAutomorphismsGeneratorT( ) #F FreeGroupAutomorphismsGeneratorQ( ) #F FreeGroupAutomorphismsGeneratorR( ) ## ## These functions return the automorphism of which maps the ## generators [, , ..., ] to ## O : [^-1 , , ..., ] (n>=1) ## P : [ , , , ..., ] (n>=2) ## U : [, , , ..., ] (n>=2) ## S : [^-1, ^-1, ..., ^-1, ^-1 ] (n>=1) ## T : [ , ^-1, , ..., ] (n>=2) ## Q : [, , ..., , ] (n>=2) ## R : [^-1, , , , ..., ## , ^-1, ^-1] (n>=4) ## InstallGlobalFunction( FreeGroupAutomorphismsGeneratorO, function( g ) local imgs; FGA_CheckRank( g, 1 ); imgs := ShallowCopy( FreeGeneratorsOfGroup( g ) ); imgs[1] := imgs[1]^-1; return FreeGroupEndomorphismByImages( g, imgs ); end ); InstallGlobalFunction( FreeGroupAutomorphismsGeneratorP, function( g ) local imgs; FGA_CheckRank( g, 2 ); imgs := ShallowCopy( FreeGeneratorsOfGroup( g ) ); imgs{[1,2]} := [ imgs[2], imgs[1] ]; return FreeGroupEndomorphismByImages( g, imgs ); end ); InstallGlobalFunction( FreeGroupAutomorphismsGeneratorU, function( g ) local imgs; imgs := ShallowCopy( FreeGeneratorsOfGroup( g ) ); FGA_CheckRank( g, 2 ); imgs[1] := imgs[1] * imgs[2]; return FreeGroupEndomorphismByImages( g, imgs ); end ); InstallGlobalFunction( FreeGroupAutomorphismsGeneratorS, function( g ) local imgs; FGA_CheckRank( g, 1 ); imgs := FreeGeneratorsOfGroup(g){[2..Rank(g)]}; Add( imgs, FreeGeneratorsOfGroup(g)[1] ); return FreeGroupEndomorphismByImages( g, List(imgs, g -> g^-1) ); end ); InstallGlobalFunction( FreeGroupAutomorphismsGeneratorT, function( g ) local imgs; FGA_CheckRank( g, 2 ); imgs := ShallowCopy( FreeGeneratorsOfGroup( g ) ); imgs{[1..2]} := [ imgs[2], imgs[1]^-1 ]; return FreeGroupEndomorphismByImages( g, imgs ); end ); InstallGlobalFunction( FreeGroupAutomorphismsGeneratorQ, function( g ) local imgs; FGA_CheckRank( g, 2 ); # we could allow 1 imgs := FreeGeneratorsOfGroup(g){[2..Rank(g)]}; Add( imgs, FreeGeneratorsOfGroup(g)[1] ); return FreeGroupEndomorphismByImages( g, imgs ); end ); InstallGlobalFunction( FreeGroupAutomorphismsGeneratorR, function( g ) local imgs, n; FGA_CheckRank( g, 4 ); n := RankOfFreeGroup( g ); imgs := ShallowCopy( FreeGeneratorsOfGroup( g ) ); imgs{[1,2,n-1,n]} := [ imgs[2]^-1, imgs[1], imgs[n]*imgs[n-1]^-1, imgs[n-1]^-1 ]; return FreeGroupEndomorphismByImages( g, imgs ); end ); ############################################################################# ## #F FGA_CheckRank( , ) ## ## Checks whether has rank at least , and signals an ## error otherwise (helper function for FreeGroupAutomorphismsGenerator*) ## InstallGlobalFunction( FGA_CheckRank, function( g, r ) if RankOfFreeGroup( g ) < r then Error( "the rank of the group should be at least ", r ); fi; return; end ); ############################################################################# ## #E fga/lib/Autom.gi0000664000371700037170000002542113275267465015226 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Autom.gi FGA package Christian Sievers ## ## Methods to create and compute with inverse automata ## #Y 2003 - 2018 ## DeclareRepresentation( "IsSimpleInvAutomatonRep", IsComponentObjectRep and IsInvAutomatonCategory and IsAttributeStoringRep and IsCollection, # [ "initial", "terminal", "states", "group" ] ); [ "states", "group" ] ); InstallMethod( TrivialInvAutomaton, [ IsFreeGroup ], function(G) local state; state := FGA_newstate(); return Objectify( NewType( FamilyObj( G ), IsSimpleInvAutomatonRep and IsMutable), rec(initial:=state, terminal:=state, group:=G) ); end ); InstallMethod( InvAutomatonInsertGenerator, IsCollsElms, [ IsSimpleInvAutomatonRep and IsMutable, IsElementOfFreeGroup ], function(A,gen) FGA_AutomInsertGeneratorLetterRep( A, LetterRepAssocWord( gen ) ); end ); InstallMethod( \in, "for a simple inverse automaton", IsElmsColls, [ IsElementOfFreeGroup, IsSimpleInvAutomatonRep ], function(g,A) return IsIdenticalObj(FGA_deltas( A!.initial, LetterRepAssocWord(g)), A!.terminal); end ); InstallMethod( PrintObj, [ IsSimpleInvAutomatonRep ], function(A) Print(""); end ); InstallMethod( AsGroup, "for a simple inverse Automaton", [ IsSimpleInvAutomatonRep ], function(A) local G; if IsMutable(A) then TryNextMethod(); fi; G := rec (); ObjectifyWithAttributes( G, NewType( FamilyObj( A ), IsFreeGroup and IsAttributeStoringRep and HasOneImmutable and HasFreeGroupAutomaton ), OneImmutable, One( A!.group ), FreeGroupAutomaton, A ); return G; end ); InstallGlobalFunction( FGA_newstate, function() return (rec (delta:=[], deltainv:=[])); end ); InstallGlobalFunction( FGA_connectpos, function(s1, s2, g) s1.delta[g] := s2; s2.deltainv[g] := s1; end ); InstallGlobalFunction( FGA_connect, function(s1, s2, g) if g>0 then FGA_connectpos(s1, s2, g); else FGA_connectpos(s2, s1, -g); fi; end ); InstallGlobalFunction( FGA_define, function(state, gen) local nstate; nstate := FGA_newstate(); FGA_connect(state, nstate, gen); return nstate; # !!! end ); # "active" InstallGlobalFunction( FGA_find, function(s) while IsBound(s.isnow) do s := s.isnow; od; return s; # todo: path compression end ); InstallGlobalFunction( FGA_merge, function(s1, s2, Q) s1 := FGA_find(s1); s2 := FGA_find(s2); if IsNotIdenticalObj(s1,s2) then s2.isnow := s1; Add(Q,s2); fi; end ); InstallGlobalFunction( FGA_coincidence, function(s1,s2) local Q, s, g, s0, s01, delta, deltainv; Q := []; FGA_merge(s1, s2, Q); for s in Q do delta := ShallowCopy(s.delta); for g in BoundPositions(delta) do Unbind(delta[g].deltainv[g]); od; deltainv := ShallowCopy(s.deltainv); for g in BoundPositions(deltainv) do Unbind(deltainv[g].delta[g]); od; for g in BoundPositions(delta) do s0 := FGA_find(s); s01 := FGA_find(delta[g]); if IsBound(s0.delta[g]) then FGA_merge(s01, s0.delta[g], Q); elif IsBound(s01.deltainv[g]) then FGA_merge(s0, s01.deltainv[g], Q); else FGA_connectpos(s0, s01, g); fi; od; for g in BoundPositions(deltainv) do s0 := FGA_find(s); s01 := FGA_find(deltainv[g]); if IsBound(s0.deltainv[g]) then FGA_merge(s01, s0.deltainv[g], Q); elif IsBound(s01.delta[g]) then FGA_merge(s0, s01.delta[g], Q); else FGA_connectpos(s01, s0, g); fi; od; od; end ); InstallGlobalFunction( FGA_delta, function(state, gen) if gen>0 then return ATf(state.delta, gen); else return ATf(state.deltainv, -gen); fi; end ); InstallGlobalFunction( FGA_deltas, function(state, genlist) return IteratedF(genlist, FGA_delta, state); end ); InstallGlobalFunction( FGA_TmpState, function(state, genlist) local undo, oldstate, i; i := 1; while state <> fail and i <= Size(genlist) do oldstate := state; state := FGA_delta( oldstate, genlist[i] ); i := i+1; od; if state = fail then i := i-1; if genlist[i] > 0 then undo := function() Unbind(oldstate.delta[genlist[i]]); end; else undo := function() Unbind(oldstate.deltainv[-genlist[i]]); end; fi; state := Iterated( genlist{[i..Size(genlist)]}, FGA_define, oldstate ); else undo := ReturnTrue; fi; return rec( state:=state, undo:=undo); end ); InstallGlobalFunction( FGA_trace, function(s,w) local i, s1; s1 := s; i := 1; while i <= Length(w) and s1 <> fail do s := s1; s1 := FGA_delta(s, w[i]); i := i+1; od; if s1 = fail then return rec(state:=s, index:=i-1); else return rec(state:=s1, index:=i); fi; end ); InstallGlobalFunction( FGA_backtrace, function(s,w,j) local i, s1; s1 := s; i := Length(w); while i >= j and s1 <> fail do s := s1; s1 := FGA_delta(s, -w[i]); i := i-1; od; if s1 = fail then return rec(state:=s, index:=i+1); else return rec(state:=s1, index:=i); fi; end ); InstallGlobalFunction( FGA_InsertGenerator, function(s, gen) return FGA_InsertGeneratorLetterRep(s, LetterRepAssocWord(gen)); end ); InstallGlobalFunction( FGA_AutomInsertGeneratorLetterRep, function(A, w) A!.initial := FGA_InsertGeneratorLetterRep( A!.initial, w); A!.terminal := A!.initial; end ); InstallGlobalFunction( FGA_InsertGeneratorLetterRep, function(s, w) local i, t, bt, s1, s2; t := FGA_trace(s, w); bt := FGA_backtrace(s, w, t.index); s1 := t.state; s2 := bt.state; if t.index > bt.index then # trace complete FGA_coincidence(s1, s2); else if IsIdenticalObj(s1, s2) then while w[t.index] = -w[bt.index] do s1 := FGA_define(s1, w[t.index]); t.index := t.index + 1; bt.index := bt.index - 1; od; s2 := s1; fi; for i in [t.index .. bt.index-1] do s1 := FGA_define(s1, w[i]); od; FGA_connect(s1, s2, w[bt.index]); fi; return FGA_find(s); end ); InstallGlobalFunction( FGA_FromGroupWithGenerators, # gens -> Iterated(gens, FGA_InsertGenerator, FGA_newstate()) ); function(G) local s; s := Iterated(GeneratorsOfGroup(G), FGA_InsertGenerator, FGA_newstate()); return Objectify( NewType( FamilyObj( G ),IsSimpleInvAutomatonRep), rec(initial:=s, terminal:=s, group:=G) ); end ); InstallGlobalFunction( FGA_FromGeneratorsLetterRep, function(gens,G) local s; s := Iterated(gens, FGA_InsertGeneratorLetterRep, FGA_newstate()); return Objectify( NewType( FamilyObj( G ), IsSimpleInvAutomatonRep and IsMutable), rec(initial:=s, terminal:=s, group:=G) ); end ); InstallGlobalFunction( FGA_Check, function(s, w) return IsIdenticalObj(FGA_deltas(s, w), s); end ); InstallGlobalFunction( FGA_FindGeneratorsAndStates, function(A) local Q, Gens, nq, q, i, nr, freegens; q := A!.initial; nr := 0; Gens := []; q.repr := []; Q := [q]; for nq in Q do freegens := []; nr := nr + 1; nq.nr := nr; for i in BoundPositions(nq.delta) do q := nq.delta[i]; if IsBound(q.repr) then if nq.repr = [] or nq.repr[Length(nq.repr)] <> -i then Add(Gens, Concatenation(nq.repr, [i], -Reversed(q.repr))); freegens[i] := Length(Gens); fi; else q.repr := ShallowCopy(nq.repr); Add(q.repr, i); Add(Q, q); fi; od; for i in BoundPositions(nq.deltainv) do q := nq.deltainv[i]; if not(IsBound(q.repr)) then q.repr := ShallowCopy(nq.repr); Add(q.repr, -i); Add(Q, q); fi; od; if freegens <> [] then nq.freegens := freegens; fi; od; ### A!.states := Q; A!.genslr := Gens; end ); InstallGlobalFunction( FGA_initial, A -> A!.initial ); InstallGlobalFunction( FGA_repr, state -> state.repr ); InstallGlobalFunction( FGA_GeneratorsLetterRep, function(A) if not IsBound( A!.genslr ) then FGA_FindGeneratorsAndStates(A); fi; return A!.genslr; end ); InstallGlobalFunction( FGA_States, function(A) if not IsBound( A!.states ) then FGA_FindGeneratorsAndStates(A); fi; return A!.states; end ); InstallGlobalFunction( FGA_reducedPos, function(A) local i, states, n; i := 0; states := FGA_States(A); repeat i := i+1; n := Size(BoundPositions(states[i].delta)) + Size(BoundPositions(states[i].deltainv)); until n > 2 or ( n=2 and i=1); return i; end ); InstallGlobalFunction( FGA_Index, function(A) local states, r; states := FGA_States(A); r := Size(FreeGeneratorsOfWholeGroup(A!.group)); if ForAny( List( states, s -> s.delta), delta -> not IsDenseList(delta) or Size(delta) <> r ) then return infinity; fi; return Size(states); end ); InstallGlobalFunction( FGA_AsWordLetterRepInFreeGenerators, function(g,A) local s,x,f,w; FGA_States(A); # do work in the automaton if needed w := []; s := A!.initial; for x in g do if x > 0 then if IsBound(s.freegens) and IsBound(s.freegens[x]) then Add(w, s.freegens[x]); fi; s := ATf(s.delta, x); if s = fail then return fail; fi; else s := ATf(s.deltainv, -x); if s=fail then return fail; fi; if IsBound(s.freegens) and IsBound(s.freegens[-x]) then Add(w, -s.freegens[-x]); fi; fi; od; if IsNotIdenticalObj( s, A!.terminal ) then return fail; fi; return w; end ); ############################################################################# ## #E fga/lib/FreeGrps.gi0000644000371700037170000001551213275267465015654 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W FreeGroups.gi FGA package Christian Sievers ## ## Main installation file for the FGA package ## #Y 2003 - 2012 ## ############################################################################# ## #M FreeGroupAutomaton( ) ## ## returns the automaton representing . ## InstallMethod( FreeGroupAutomaton, "for a subgroup of a free group", [ CanComputeWithInverseAutomaton ], function(G) return FGA_FromGroupWithGenerators(G); end ); ############################################################################# ## #M FreeGroupExtendedAutomaton( ) ## ## return the extended automaton representing . InstallMethod( FreeGroupExtendedAutomaton, "for a subgroup of a free group", [ CanComputeWithInverseAutomaton ], function(G) return FGA_FromGroupWithGeneratorsX(G); end ); ############################################################################# ## #M \in( , ) ## ## tests whether is in the finitely generated free group . ## InstallMethod( \in, "for a subgroup of a free group", IsElmsColls, [ IsElementOfFreeGroup, CanComputeWithInverseAutomaton ], function( g, G ) return g in FreeGroupAutomaton(G); end ); ############################################################################# ## #M FreeGeneratorsOfGroup( ) ## ## returns a list of free generators of the group . ## This is a minimal generating set, but is also guarantied to ## be N-reduced. ## InstallMethod( FreeGeneratorsOfGroup, "for a subgroup of a free group", [ CanComputeWithInverseAutomaton ], function(G) return List(FGA_GeneratorsLetterRep(FreeGroupAutomaton(G)), l -> AssocWordByLetterRep (ElementsFamily(FamilyObj(G)), l) ); end ); ############################################################################# ## #M GeneratorsOfGroup( ) ## InstallMethod( GeneratorsOfGroup, "for a subgroup of a free group having a FreeGroupAutomaton", [ HasFreeGroupAutomaton ], FreeGeneratorsOfGroup ); ## ## FreeGeneratorsOfGroup are GeneratorsOfGroup ## InstallImmediateMethod( GeneratorsOfGroup, HasFreeGeneratorsOfGroup, 0, FreeGeneratorsOfGroup); ############################################################################# ## #M MinimalGeneratingSet( ) ## ## returns 's FreeGeneratorsOfGroup ## InstallMethod( MinimalGeneratingSet, "for a subgroup of a free group", [ CanComputeWithInverseAutomaton ], FreeGeneratorsOfGroup ); ############################################################################# ## #M SmallGeneratingSet( ) ## ## returns 's FreeGeneratorsOfGroup ## InstallMethod( SmallGeneratingSet, "for a subgroup of a free group", [ CanComputeWithInverseAutomaton ], FreeGeneratorsOfGroup ); ############################################################################# ## #M IsWholeFamily( ) ## InstallMethod( IsWholeFamily, "for a finitely generated free group", [ CanComputeWithInverseAutomaton ], G -> ForAll( FreeGeneratorsOfWholeGroup( G ), gen -> gen in G) ); ############################################################################# ## #M RankOfFreeGroup( ) ## ## returns the rank of a free group. ## InstallMethod( RankOfFreeGroup, "for a subgroup of a free group", [ CanComputeWithInverseAutomaton ], G -> Size(MinimalGeneratingSet(G)) ); InstallMethod( RankOfFreeGroup, "for a whole free group", [ IsFreeGroup and IsWholeFamily ], G -> Size(FreeGeneratorsOfWholeGroup(G)) ); ############################################################################# ## #M Rank( ) ## ## a convenient name for RankOfFreeGroup ## InstallMethod( Rank, "for a subgroup of a free group", [ IsFreeGroup ], RankOfFreeGroup ); ############################################################################# ## #M IsSubset( , ) ## InstallMethod( IsSubset, "for subgroups of free groups", IsIdenticalObj, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton ], function(G,U) local gens; if HasFreeGeneratorsOfGroup(U) then gens := FreeGeneratorsOfGroup(U); else gens := GeneratorsOfGroup(U); fi; return ForAll(gens, u -> u in G); end ); ############################################################################# ## #M \=( , ) ## InstallMethod( \=, "for subgroups of free groups", IsIdenticalObj, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton ], function( G, H ) return IsSubset(G,H) and IsSubset(H,G); end ); ############################################################################# ## #M AsWordLetterRepInFreeGenerators( , ) ## ## returns the unique list representing a word in letter representation ## such that ## = Product( , ## x -> FreeGeneratorsOfGroup()[AbsInt(x)]^(SignInt(x)), ## One() ) ## or fail, if is not in . ## InstallMethod( AsWordLetterRepInFreeGenerators, "for an element in a free group", IsElmsColls, [ IsElementOfFreeGroup, CanComputeWithInverseAutomaton ], function( g, G ) return FGA_AsWordLetterRepInFreeGenerators( LetterRepAssocWord(g), FreeGroupAutomaton(G) ); end ); ############################################################################# ## #M AsWordLetterRepInGenerators( , ) ## ## returns a list representing a word in letter representation such that ## = Product( , ## x -> GeneratorsOfGroup()[AbsInt(x)]^(SignInt(x)), ## One() ) ## or fail, if is not in . ## InstallMethod( AsWordLetterRepInGenerators, "for an element in a free group", IsElmsColls, [ IsElementOfFreeGroup, CanComputeWithInverseAutomaton and HasGeneratorsOfGroup ], function( g, G ) return FGA_AsWordLetterRepInGenerators( LetterRepAssocWord( g ), FreeGroupExtendedAutomaton( G ) ); end ); ############################################################################# ## #O CyclicallyReducedWord( ) ## ## returns the the cyclically reduced form of ## InstallMethod( CyclicallyReducedWord, "for an element in a free group", [ IsElementOfFreeGroup ], function( g ) local rep, len, i; if IsOne( g ) then return g; fi; rep := LetterRepAssocWord( g ); len := Length( rep ); i := 1; while rep[i] = -rep[len-i+1] do i := i+1; od; return AssocWordByLetterRep( FamilyObj( g ), rep{[i..len-i+1]} ); end ); ############################################################################# ## #E fga/lib/ExtAutom.gd0000644000371700037170000000224413275267465015676 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W ExtAutom.gd FGA package Christian Sievers ## ## Declarations for methods to create and compute with ## extended inverse automata ## #Y 2003 - 2012 ## DeclareGlobalVariable( "FGA_FreeGroupForGenerators" ); DeclareGlobalVariable( "FGA_One" ); DeclareGlobalFunction( "FGA_newstateX" ); DeclareGlobalFunction( "FGA_connectposX" ); DeclareGlobalFunction( "FGA_connectX" ); DeclareGlobalFunction( "FGA_defineX" ); DeclareGlobalFunction( "FGA_findX" ); DeclareGlobalFunction( "FGA_mergeX" ); DeclareGlobalFunction( "FGA_coincidenceX" ); DeclareGlobalFunction( "FGA_atfX" ); DeclareGlobalFunction( "FGA_deltaX" ); DeclareGlobalFunction( "FGA_stepX" ); DeclareGlobalFunction( "FGA_deltasX" ); DeclareGlobalFunction( "FGA_traceX" ); DeclareGlobalFunction( "FGA_backtraceX" ); DeclareGlobalFunction( "FGA_insertgeneratorX" ); DeclareGlobalFunction( "FGA_fromgeneratorsX" ); DeclareGlobalFunction( "FGA_FromGroupWithGeneratorsX" ); DeclareGlobalFunction( "FGA_AsWordLetterRepInGenerators" ); ############################################################################# ## #E fga/lib/Iterated.gi0000644000371700037170000000362513275267465015702 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Iterated.gi FGA package Christian Sievers ## ## Method installations for variants of Iterated ## ## Maybe this should move to the GAP library ## #Y 2003 - 2012 ## ############################################################################# ## #M Iterated( , , ) ## ## applies to iteratively as Iterated does, but uses ## as initial value. ## InstallOtherMethod( Iterated, [ IsList, IsFunction, IsObject ], function (list, f, init) local x; for x in list do init := f(init, x); od; return init; end ); ############################################################################# ## #M IteratedF( , ) ## ## applies to iteratively as Iterated does, but stops ## and returns fail when returns fail. InstallMethod( IteratedF, [ IsList, IsFunction ], function (list, f) local res, i; if IsEmpty( list ) then Error( "IteratedF: must contain at least one element" ); fi; res := list[1]; for i in [ 2 .. Length( list ) ] do if res = fail then break; fi; res := f( res, list[i] ); od; return res; end ); ############################################################################# ## #M IteratedF( , , ) ## ## applies to iteratively as Iterated does, but stops ## and returns fail when returns fail, and uses as ## initial value. InstallOtherMethod( IteratedF, [ IsList, IsFunction, IsObject ], function (list, f, init) local x; for x in list do init := f(init, x); if init=fail then break; fi; od; return init; end ); ############################################################################# ## #E fga/lib/FreeGrps.gd0000644000371700037170000000652613275267465015654 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W FreeGroups.gd FGA package Christian Sievers ## ## Main declaration file for the FGA package ## #Y 2003 - 2012 ## ############################################################################# ## #A FreeGeneratorsOfGroup( ) ## ## returns a list of free generators of the group . ## This is a minimal generating set, but is also guarantied to ## be N-reduced. ## DeclareAttribute( "FreeGeneratorsOfGroup", IsFreeGroup ); ############################################################################# ## #A RankOfFreeGroup( ) ## ## returns the rank of a free group. ## DeclareAttribute( "RankOfFreeGroup", IsFreeGroup ); ############################################################################# ## #A FreeGroupAutomaton( ) ## ## returns the automaton representing . ## DeclareAttribute( "FreeGroupAutomaton", IsFreeGroup, "mutable" ); ############################################################################# ## #A FreeGroupExtendedAutomaton( ) ## ## return the extended automaton representing . ## The extra information is enough for a constructive membership test ## with respect to the given generators of . ## DeclareAttribute( "FreeGroupExtendedAutomaton", IsFreeGroup ); ############################################################################# ## #O AsWordLetterRepInFreeGenerators( , ) ## ## returns the unique list representing a word in letter representation ## such that ## = Product( , ## x -> FreeGeneratorsOfGroup()[AbsInt(x)]^(SignInt(x)), ## One() ) ## or fail, if is not in . ## DeclareOperation( "AsWordLetterRepInFreeGenerators", [ IsElementOfFreeGroup, IsFreeGroup ] ); ############################################################################# ## #O AsWordLetterRepInGenerators( , ) ## ## returns a list representing a word in letter representation such that ## = Product( , ## x -> GeneratorsOfGroup()[AbsInt(x)]^(SignInt(x)), ## One() ) ## or fail, if is not in . ## DeclareOperation( "AsWordLetterRepInGenerators", [ IsElementOfFreeGroup, IsFreeGroup ] ); ############################################################################# ## #O CyclicallyReducedWord( ) ## ## returns the the cyclically reduced form of ## DeclareOperation( "CyclicallyReducedWord", [ IsElementOfFreeGroup ] ); ############################################################################# ## #F CanComputeWithInverseAutomaton( ) ## ## indicates whether we can use inverse automata to compute with . ## We assume this is possible if is a finitely generated free group, ## hoping that we actually can get a generating set when needed. ## This is not always true, but generally then there is also no other way. ## DeclareSynonym( "CanComputeWithInverseAutomaton", IsFreeGroup and IsFinitelyGeneratedGroup ); InstallTrueMethod( CanComputeWithInverseAutomaton, HasFreeGroupAutomaton ); InstallTrueMethod( CanEasilyTestMembership, HasFreeGroupAutomaton ); InstallTrueMethod( CanComputeSizeAnySubgroup, IsFreeGroup ); ############################################################################# ## #E fga/lib/Hom.gd0000644000371700037170000000147513275267465014660 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Hom.gd FGA package Christian Sievers ## ## Declaration file for the computation with homomorphisms of free groups ## #Y 2012 ## ############################################################################# ## #A FGA_Source( ) ## ## returns the source of as group with special generators ## DeclareAttribute( "FGA_Source", IsFromFpGroupGeneralMappingByImages ); ############################################################################# ## #A FGA_Image( ) ## ## returns the image of as group with special generators ## DeclareAttribute( "FGA_Image", IsToFpGroupGeneralMappingByImages ); ############################################################################# ## #E fga/lib/Hom.gi0000644000371700037170000000537213275267465014665 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Hom.gi FGA package Christian Sievers ## ## Methods for homomorphisms of free groups ## #Y 2003 - 2016 ## InstallMethod( PreImagesRepresentative, "for homomorphisms of free groups", FamRangeEqFamElm, [ IsToFpGroupGeneralMappingByImages, IsElementOfFreeGroup ], function( hom, x ) local w, mgi; mgi := MappingGeneratorsImages( hom ); w := AsWordLetterRepInGenerators( x, FGA_Image( hom )); if w = fail then return fail; fi; return Product( w, i -> mgi[1][AbsInt(i)]^SignInt(i), One(Source(hom))); end ); InstallMethod( ImagesRepresentative, "for homomorphisms of free groups", FamSourceEqFamElm, [ IsFromFpGroupGeneralMappingByImages, IsElementOfFreeGroup ], 23, function( hom, x ) local w, mgi; mgi := MappingGeneratorsImages( hom ); if mgi[1]=[] then return One(Range(hom)); fi; w := AsWordLetterRepInGenerators( x, FGA_Source( hom )); if w = fail then return fail; fi; return Product( w, i -> mgi[2][AbsInt(i)]^SignInt(i), One(Range(hom))); end ); InstallMethod( FGA_Source, [ IsFromFpGroupGeneralMappingByImages and HasMappingGeneratorsImages ], hom -> SubgroupNC( Source(hom), MappingGeneratorsImages(hom)[1] ) ); InstallMethod( FGA_Image, [ IsToFpGroupGeneralMappingByImages and HasMappingGeneratorsImages ], hom -> SubgroupNC( Range(hom), MappingGeneratorsImages(hom)[2] ) ); InstallMethod( IsSingleValued, "for group general mappings of free groups", [ IsFromFpGroupGeneralMappingByImages and HasMappingGeneratorsImages ], function( hom ) local mgi, g, imgs; mgi := MappingGeneratorsImages( hom ); if mgi[1]=[] then return true; fi; # map on trivial group g := SubgroupNC( Source(hom), mgi[1] ); if not IsFreeGroup( g ) then TryNextMethod(); fi; if Size( mgi[1] ) = RankOfFreeGroup( g ) then return true; fi; # write free generators in given generators and # compute corresponding images: imgs := List( FreeGeneratorsOfGroup( g ), fgen -> Product( AsWordLetterRepInGenerators( fgen, g ), i -> mgi[2][AbsInt(i)]^SignInt(i), One(Range(hom)) )); # check if all given generator/image pairs agree with the # map given by free generators and computed images: return ForAll( [ 1 .. Size( mgi[1] ) ], n -> mgi[2][n] = Product( AsWordLetterRepInFreeGenerators( mgi[1][n], g ), i -> imgs[AbsInt(i)]^SignInt(i), One(Range(hom)) )); end ); ############################################################################# ## #E fga/lib/ReprAct.gi0000644000371700037170000001274513275267465015504 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W ReprAct.gi FGA package Christian Sievers ## ## Methods for computing RepresentativeAction ## #Y 2003 - 2016 ## InstallOtherMethod( RepresentativeActionOp, "for conjugation of elements in a free group", IsCollsElmsElmsX, [ IsFreeGroup, IsElementOfFreeGroup, IsElementOfFreeGroup, IsFunction ], function(F, d, e, act) local wd, we, le, ld, id, ie, wecr, w, pos, pos2, conj; if act <> OnPoints then TryNextMethod(); fi; if IsOne(d) and IsOne(e) then return One(F); fi; if IsOne(d) or IsOne(e) then return fail; fi; wd := LetterRepAssocWord(d); ld := Length(wd); id := 1; while wd[id] = -wd[ld-id+1] do id := id+1; od; we := LetterRepAssocWord(e); le := Length(we); ie := 1; while we[ie] = -we[le-ie+1] do ie := ie+1; od; if ld-2*id <> le-2*ie then return fail; fi; w := wd{[id..ld-id+1]}; # wd cyclically reduced w := Concatenation(w,w); # ... and doubled wecr := we{[ie..le-ie+1]}; # we cyclically reduced pos := PositionSublist(w,wecr); if pos=fail then return fail; fi; conj := AssocWordByLetterRep(FamilyObj(d), wd{[1..id+pos-2]}) * AssocWordByLetterRep(FamilyObj(d), we{[le-ie+2..le]}); if conj in F then return conj; fi; pos2 := PositionSublist(w, wecr, pos); if pos2=fail then pos2 := pos+ld-2*ie+2; fi; return FindPowLetterRep(F, wd{[1..id+pos-2]},w{[pos..pos2-1]}, we{[le-ie+2..le]}); end ); InstallMethod( FindPowLetterRep, [ CanComputeWithInverseAutomaton, IsList, IsList, IsList ], function(f, wi, wp, wt) local init, initstate, final, finalstate, state, n, fam; state := FGA_initial(FreeGroupAutomaton(f)); init := FGA_TmpState(state, wi); initstate := init.state; final := FGA_TmpState(state, -Reversed(wt)); finalstate := final.state; state := initstate; n := 0; repeat state := FGA_deltas(state, wp); n := n+1; until state=fail or IsIdenticalObj(state, initstate) or IsIdenticalObj(state, finalstate); if state = fail then state := initstate; n := 0; wp := -Reversed(wp); repeat state := FGA_deltas(state, wp); n := n+1; until state=fail or IsIdenticalObj(state, finalstate); fi; final.undo(); init.undo(); if IsIdenticalObj(state, finalstate) then fam := ElementsFamily(FamilyObj(f)); return AssocWordByLetterRep(fam, wi) * AssocWordByLetterRep(fam, wp)^n * AssocWordByLetterRep(fam, wt); else return fail; fi; end ); InstallOtherMethod( RepresentativeActionOp, "for subgroups of a free group", IsFamFamFamX, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton, IsFunction ],1, function(F, G, H, act) local AG, AH, AF, rdG, rdH, statesH, redgens, i, AN, tmp, conj; if act <> OnPoints then TryNextMethod(); fi; if RankOfFreeGroup(G) <> RankOfFreeGroup(H) then return fail; fi; AG := FreeGroupAutomaton(G); rdG := FGA_reducedPos(AG); AH := FreeGroupAutomaton(H); rdH := FGA_reducedPos( AH ); statesH := FGA_States(AH); if Size(statesH)-rdH <> Size(FGA_States(AG))-rdG then return fail; fi; redgens := List( List(FreeGeneratorsOfGroup(G), LetterRepAssocWord), w -> w{[rdG .. Length(w)-rdG+1]} ); for i in [rdH .. Size(statesH)] do if ForAll(redgens, w -> FGA_Check(statesH[i], w)) then # We now know that G is a subgroup of a conjugate of H. # More ugly low level computation could check for equality. # Instead we postpone the check to a time where we can work # at a higher level. # So if the result is fail, we get it a little slower. AN := FreeGroupAutomaton( NormalizerInWholeGroup( G ) ); tmp := FGA_TmpState( AN!.initial, Concatenation( FGA_States( AG )[ rdG ].repr, -Reversed(FGA_repr(statesH[i])) )); AF := FreeGroupAutomaton( F ); conj := FGA_FindRepInIntersection( AF, AF!.terminal, AN, tmp.state ); tmp.undo(); if conj = fail then return fail; fi; conj := AssocWordByLetterRep( ElementsFamily(FamilyObj(F)), conj ); # Now check if we really have a conjugating element: if IsSubset( G, List( FreeGeneratorsOfGroup(H), h -> h^(conj^-1) )) then return conj; else return fail; fi; fi; od; return fail; end ); ############################################################################# ## #E fga/lib/Index.gi0000644000371700037170000000573413275267465015213 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Index.gi FGA package Christian Sievers ## ## Method installations for index computations in free groups ## #Y 2003 - 2012 ## ############################################################################# ## #M IndexInWholeGroup( ) ## InstallMethod( IndexInWholeGroup, "for a free group", [ CanComputeWithInverseAutomaton ], function(G) if HasIsWholeFamily(G) and IsWholeFamily(G) then return 1; fi; # let the gap lib handle this case: if IsSubgroupOfWholeGroupByQuotientRep(G) then TryNextMethod(); fi; return FGA_Index(FreeGroupAutomaton(G)); end ); ############################################################################# ## #M IndexOp( , , ) ## ## computes the index of in . ## If is true, checks whether the subgroup relation really holds ## and returns fail otherwise. ## Some of the checks will even be performed when is false. ## InstallOtherMethod( IndexOp, "for free groups", IsFamFamX, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton, IsBool ], function( G, U, check ) local indexG, indexU, index, rankG, gensU, gen, w, genwords; indexG := IndexInWholeGroup( G ); indexU := IndexInWholeGroup( U ); if indexG <> infinity then if check and not IsSubset( G, U ) then return fail; fi; if indexU = infinity then return infinity; else index := indexU / indexG; if IsInt( index ) then return index; else return fail; fi; fi; fi; # one more cheap test: if indexU <> infinity then return fail; fi; # now we must work harder rankG := RankOfFreeGroup( G ); gensU := FreeGeneratorsOfGroup( U ); genwords := []; for gen in gensU do w := AsWordLetterRepInFreeGenerators( gen, G ); if w = fail then return fail; fi; Add( genwords, w ); od; return FGA_Index( FGA_FromGeneratorsLetterRep( genwords, FreeGroup(rankG) ) ); end ); ############################################################################# ## #M IndexOp( , ) ## InstallMethod( IndexOp, "for free groups", IsIdenticalObj, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton ], function( G, H ) return IndexOp( G, H, true); end ); ############################################################################# ## #M IndexNC( , ) ## InstallMethod( IndexNC, "for free groups", IsIdenticalObj, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton ], function( G, H ) return IndexOp( G, H, false); end ); ############################################################################# ## #E fga/lib/ReprActT.gi0000644000371700037170000000164713275267465015627 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W ReprActT.gi FGA package Christian Sievers ## ## Trivial cases for RepresentativeAction ## ## This is generally applicable and not needed for the FGA package, ## so maybe it should move to the GAP library. ## #Y 2003 - 2012 ## InstallOtherMethod( RepresentativeActionOp, "trivial general cases", IsCollsElmsElmsX, [ IsGroup, IsObject, IsObject, IsFunction ], function( G, d, e, act) local result; if act=OnRight then result := LeftQuotient( d, e ); elif act=OnLeftInverse then result := d / e; else TryNextMethod(); fi; if result in G then return result; else return fail; fi; end ); ############################################################################# ## #E fga/lib/Iterated.gd0000644000371700037170000000121513275267465015666 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Iterated.gd FGA package Christian Sievers ## ## Declarations for variants of Iterated ## ## Maybe this should move to the GAP library ## #Y 2003 - 2012 ## ############################################################################# ## #O IteratedF( , ) ## ## applies to iteratively as Iterated does, but stops ## and returns fail when returns fail. ## DeclareOperation( "IteratedF", [ IsList, IsFunction ] ); ############################################################################# ## #E fga/lib/util.gi0000644000371700037170000000102213275267465015103 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W util.gi FGA package Christian Sievers ## ## Utility functions ## #Y 2003 - 2012 ## InstallGlobalFunction( BoundPositions, l -> Filtered([1..Length(l)], i -> IsBound(l[i])) ); InstallGlobalFunction( ATf, function(l, p) if IsBound(l[p]) then return l[p]; else return fail; fi; end ); ############################################################################# ## #E fga/lib/ReprAct.gd0000644000371700037170000000063413275267465015471 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W ReprAct.gd FGA package Christian Sievers ## ## Declarations used for computing RepresentativeAction ## #Y 2003 - 2012 ## DeclareOperation( "FindPowLetterRep", [ IsFreeGroup, IsList, IsList, IsList ]); ############################################################################# ## #E fga/lib/Intsect.gi0000644000371700037170000001340313275267465015545 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Intsect.gi FGA package Christian Sievers ## ## Installations for the computation of intersections of free groups ## #Y 2003 - 2012 ## ############################################################################# ## #F FGA_StateTable( , , ) ## InstallGlobalFunction( FGA_StateTable, function( t, i, j ) if not IsBound( t[i] ) then t[i] := []; fi; if not IsBound( t[i][j] ) then t[i][j] := FGA_newstate(); fi; return t[i][j]; end ); ############################################################################# ## #M Intersection2( , ) ## InstallMethod( Intersection2, "for subgroups of free groups", IsIdenticalObj, [ CanComputeWithInverseAutomaton, CanComputeWithInverseAutomaton ], function( G1, G2 ) local A, t, sl1, sl2, i, nr1, nr2, Q, pair, g, q, q1, q2, bpd, bpdi; # let the gap lib handle this case: if IsSubgroupOfWholeGroupByQuotientRep( G1 ) and IsSubgroupOfWholeGroupByQuotientRep( G2 ) then TryNextMethod(); fi; t := []; i := FGA_StateTable( t, 1, 1 ); sl1 := FGA_States( FreeGroupAutomaton( G1 ) ); sl2 := FGA_States( FreeGroupAutomaton( G2 ) ); Q := [ [1,1] ]; for pair in Q do q1 := sl1[ pair[1] ]; q2 := sl2[ pair[2] ]; q := FGA_StateTable( t, pair[1], pair[2] ); for g in Difference( Intersection( BoundPositions( q1.delta ), BoundPositions( q2.delta ) ), BoundPositions( q.delta ) ) do nr1 := q1.delta[g].nr; nr2 := q2.delta[g].nr; FGA_connectpos( q, FGA_StateTable( t, nr1, nr2 ), g ); Add( Q, [ nr1, nr2 ] ); od; for g in Difference( Intersection( BoundPositions( q1.deltainv ), BoundPositions( q2.deltainv ) ), BoundPositions( q.deltainv ) ) do nr1 := q1.deltainv[g].nr; nr2 := q2.deltainv[g].nr; FGA_connectpos( FGA_StateTable( t, nr1, nr2 ), q, g ); Add( Q, [ nr1, nr2 ] ); od; bpd := BoundPositions( q.delta ); bpdi := BoundPositions( q.deltainv ); while Size( bpd ) + Size( bpdi ) = 1 and IsNotIdenticalObj( q, i ) do if Size( bpd ) = 1 then g := bpd[ 1 ]; q := q.delta[ g ]; Unbind( q.deltainv[ g ] ); else g := bpdi[ 1 ]; q := q.deltainv[ g ]; Unbind( q.delta[ g ] ); fi; bpd := BoundPositions( q.delta ); bpdi := BoundPositions( q.deltainv ); od; od; A := Objectify( NewType( FamilyObj( G1 ), IsSimpleInvAutomatonRep ), rec( initial:=i, terminal:=i, group := TrivialSubgroup( G1 ) ) ); return AsGroup( A ); end ); ############################################################################# ## #F FGA_TrySetRepTable( , , , , ) ## InstallGlobalFunction( FGA_TrySetRepTable, function( t, i, j, r, g ) local rx; if not IsBound( t[i] ) then t[i] := []; fi; if not IsBound( t[i][j] ) then rx := ShallowCopy( r ); Add( rx, g ); t[i][j] := rx; return rx; else return fail; fi; end ); ############################################################################# ## #F FGA_GetNr ( , ) ## InstallGlobalFunction( FGA_GetNr, function( q, sl ) if not IsBound( q.nr ) then Add( sl, q ); q.nr := Size( sl ); elif not IsBound( sl[ q.nr ] ) then sl[ q.nr ] := q; fi; return q.nr; end ); ############################################################################# ## #F FGA_FindRepInIntersection ( , , , ) ## InstallGlobalFunction( FGA_FindRepInIntersection, function( A1, t1, A2, t2 ) local tab, sl1, sl2, Q, pair, g, q1, nr1, q2, nr2, r, rx; sl1 := []; sl2 := []; q1 := A1!.initial; q2 := A2!.initial; if IsIdenticalObj( q1, t1) and IsIdenticalObj( q2, t2) then return []; fi; nr1 := FGA_GetNr( q1, sl1 ); nr2 := FGA_GetNr( q2, sl2 ); tab := []; tab [ nr1 ] := []; tab [ nr1 ][ nr2 ] := []; # empty word at initial state Q := [ [ nr1, nr2 ] ]; for pair in Q do q1 := sl1[ pair[1] ]; q2 := sl2[ pair[2] ]; r := tab [ pair[1] ] [ pair[2] ]; for g in Intersection( BoundPositions( q1.delta ), BoundPositions( q2.delta ) ) do nr1 := FGA_GetNr(q1.delta[g], sl1); nr2 := FGA_GetNr(q2.delta[g], sl2); rx := FGA_TrySetRepTable( tab, nr1, nr2, r, g ); if rx <> fail then if IsIdenticalObj(sl1[ nr1 ], t1) and IsIdenticalObj(sl2[ nr2 ], t2) then return rx; fi; Add( Q, [ nr1, nr2 ] ); fi; od; for g in Intersection( BoundPositions( q1.deltainv ), BoundPositions( q2.deltainv ) ) do nr1 := FGA_GetNr(q1.deltainv[g], sl1); nr2 := FGA_GetNr(q2.deltainv[g], sl2); rx := FGA_TrySetRepTable( tab, nr1, nr2, r, -g ); if rx <> fail then if IsIdenticalObj(sl1[ nr1 ], t1) and IsIdenticalObj(sl2[ nr2 ], t2) then return rx; fi; Add( Q, [ nr1, nr2 ] ); fi; od; od; return fail; end ); ############################################################################# ## #E fga/lib/util.gd0000644000371700037170000000057613275267465015113 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W util.gd FGA package Christian Sievers ## ## Declarations of utility functions ## #Y 2003 - 2012 ## DeclareGlobalFunction( "BoundPositions" ); DeclareGlobalFunction( "ATf" ); ############################################################################# ## #E fga/lib/AutGrp.gd0000644000371700037170000000520613275267465015333 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W AutGrp.gd FGA package Christian Sievers ## ## Methods for automorphism groups of free groups ## #Y 2003 - 2012 ## ############################################################################# ## #F IsAutomorphismGroupOfFreeGroup( ) ## ## returns true if is the automorphism group of a free group. ## DeclareFilter( "IsAutomorphismGroupOfFreeGroup" ); InstallTrueMethod( IsAutomorphismGroup, IsAutomorphismGroupOfFreeGroup ); ############################################################################# ## #F FreeGroupEndomorphismByImages( , ) ## ## returns the endomorphism of that maps the generators of ## to . ## DeclareGlobalFunction( "FreeGroupEndomorphismByImages" ); ############################################################################# ## #F FreeGroupAutomorphismsGeneratorO( ) #F FreeGroupAutomorphismsGeneratorP( ) #F FreeGroupAutomorphismsGeneratorU( ) #F FreeGroupAutomorphismsGeneratorS( ) #F FreeGroupAutomorphismsGeneratorT( ) #F FreeGroupAutomorphismsGeneratorQ( ) #F FreeGroupAutomorphismsGeneratorR( ) ## ## These functions return the automorphism of which maps the ## generators [, , ..., ] to ## O : [^-1 , , ..., ] (n>=1) ## P : [ , , , ..., ] (n>=2) ## U : [, , , ..., ] (n>=2) ## S : [^-1, ^-1, ..., ^-1, ^-1 ] (n>=1) ## T : [ , ^-1, , ..., ] (n>=2) ## Q : [, , ..., , ] (n>=2) ## R : [^-1, , , , ..., ## , ^-1, ^-1] (n>=4) ## DeclareGlobalFunction( "FreeGroupAutomorphismsGeneratorO" ); DeclareGlobalFunction( "FreeGroupAutomorphismsGeneratorP" ); DeclareGlobalFunction( "FreeGroupAutomorphismsGeneratorU" ); DeclareGlobalFunction( "FreeGroupAutomorphismsGeneratorS" ); DeclareGlobalFunction( "FreeGroupAutomorphismsGeneratorT" ); DeclareGlobalFunction( "FreeGroupAutomorphismsGeneratorQ" ); DeclareGlobalFunction( "FreeGroupAutomorphismsGeneratorR" ); ############################################################################# ## #F FGA_CheckRank( , ) ## ## Checks whether has rank at least , and signals an ## error otherwise (helper function for FreeGroupAutomorphismsGenerator*) ## DeclareGlobalFunction( "FGA_CheckRank" ); ############################################################################# ## #E fga/lib/Intsect.gd0000644000371700037170000000210413275267465015534 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Intsect.gd FGA package Christian Sievers ## ## The declaration file for the computation of intersections of free groups ## #Y 2003 - 2012 ## ## These are all helper functions: ############################################################################# ## #F FGA_StateTable(
, , ) ## DeclareGlobalFunction( "FGA_StateTable" ); ############################################################################# ## #F FGA_TrySetRepTable( , , , , ) ## DeclareGlobalFunction( "FGA_TrySetRepTable" ); ############################################################################# ## #F FGA_GetNr ( , ) ## DeclareGlobalFunction( "FGA_GetNr" ); ############################################################################# ## #F FGA_FindRepInIntersection ( , , , ) ## DeclareGlobalFunction( "FGA_FindRepInIntersection" ); ############################################################################# ## #E fga/lib/Whitehd.gi0000644000371700037170000001570113275267465015533 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Whitehd.gi FGA package Christian Sievers ## ## Computations with Whitehead automorphisms ## #Y 2004 - 2012 ## InstallMethod( FGA_WhiteheadAutomorphisms, "for finitely generated free groups", [ CanComputeWithInverseAutomaton ], function( G ) local ngens, ngen, combs, auts, L, R; ngens := [ 1 .. RankOfFreeGroup( G ) ]; auts := []; for ngen in ngens do combs := Combinations( Difference( ngens, [ngen] )); for L in combs do for R in combs do if L <> [] or R <> [] then Add( auts, FGA_WhiteheadAutomorphism( G, ngen, L, R )); fi; od; od; od; return auts; end ); InstallMethod( FGA_NielsenAutomorphisms, "for finitely generated free groups", [ CanComputeWithInverseAutomaton ], G -> Filtered( f -> FGA_WhiteheadParams(f).isnielsen ) ); InstallGlobalFunction( FGA_WhiteheadAutomorphism, function( G, ngen, L, R ) local gens, gen, ng, g, img, imginv, imgs, imgsinv, aut, autinv; imgs := []; imgsinv := []; gens := GeneratorsOfGroup( G ); gen := gens[ngen]; for ng in [ 1 .. RankOfFreeGroup( G ) ] do img := gens[ng]; imginv := img; if ng in L then img := LeftQuotient( gen, img ); imginv := gen * imginv; fi; if ng in R then img := img * gen; imginv := imginv / gen; fi; Add( imgs, img ); Add( imgsinv, imginv); od; aut := GroupHomomorphismByImagesNC( G, G, GeneratorsOfGroup(G), imgs ); autinv := GroupHomomorphismByImagesNC( G, G, GeneratorsOfGroup(G), imgsinv ); SetInverse( aut, autinv ); SetInverse( autinv, aut ); SetFGA_WhiteheadParams( aut , rec( gen := ngen, L := L, R := R, isnielsen := Length(L)+Length(R)=1 ) ); SetFGA_WhiteheadParams( autinv, true ); return aut; end ); InstallGlobalFunction( FGA_WhiteheadAnalyse, function( whs, elm, act , len , val, comb , combrest ) # [w] * e * (e*w->e) * (e->Int) * v * (v*w->v) * (v*e->r) -> r local l, newl, wh, bestwh , newelm, bestnewelm; # Int , w , Maybe w, e l := len( elm ); while true do bestwh := fail; for wh in whs do newelm := act( elm, wh ); newl := len( newelm ); if newl < l then l := newl; bestwh := wh; bestnewelm := newelm; fi; od; if bestwh=fail then return combrest( val, elm ); fi; val := comb( val, bestwh ); elm := bestnewelm; od; # not reached end ); ######################################################################## # Equation numbers and pages refer to # Jakob Nielsen: Die Isomorphismengruppe der freien Gruppen # see ../doc/manual.bib ######################################################################## InstallGlobalFunction( FGA_WhiteheadToPQOU, function ( w , p , q , o , u ) # w * g * g * g * g -> g local n ,g, whp, word, sign, nik; n := RankOfFreeGroup( Source ( w ) ); if FGA_WhiteheadParams(w) = true then w := Inverse(w); sign := -1; else sign := 1; fi; whp:= FGA_WhiteheadParams(w); word := One(p); for g in [ 1 .. n ] do if g in whp.L or g in whp.R then # using and possibly combining eq. (12) and (11) # for V_{g,gen}^-1 and U_{g,gen} nik := FGA_NikToPQ( g, whp.gen, p, q ); word := word * nik^-1; if g in whp.L then word := word * o * u^sign * o; # eq. (7) fi; if g in whp.R then word := word * u^sign; fi; word := word * nik; fi; od; return word; end ); InstallGlobalFunction( FGA_NikToPQ, function( i , k , p , q ) # Int * g * g * g -> g # eq. (8) local l; l := k-i; if i g # follows from eq. at the middle of page 171 return q^(2-i)*p*(q*p)^(i-2); end ); InstallGlobalFunction( FGA_ExtSymListRepToPQO, function( target, p , q , o ) # [Int] * g * g * g -> g local rank, word1, word2, lastshift, i, t, f2, P, Q, Pperm, Qperm, homperm, homrep, perm; f2 := FreeGroup("P","Q"); P := f2.1; Q := f2.2; word1 := One(p); word2 := word1; rank := Length( target ); Pperm := (1,2); Qperm := PermList(Concatenation([2..rank],[1])); homperm := GroupHomomorphismByImagesNC( f2, SymmetricGroup( rank ), GeneratorsOfGroup(f2), [ Pperm, Qperm ] ); homrep := GroupHomomorphismByImagesNC( f2, Group( p, q ), GeneratorsOfGroup( f2 ), [ p, q ] ); # first get rid of extendedness, using o and q lastshift := 1; for i in [ 1 .. rank ] do if not IsPosInt( target[i] ) then word1 := word1 * q^(lastshift-i) * o; lastshift := i; target[i] := AbsInt(target[i]); fi; od; word1 := word1 * q^(lastshift-1); # now target is a permutation, represent it as such target := SortingPerm(target); # decompose it as product of powers of T_i, compare p. 171 while not IsOne( target ) do i := LargestMovedPoint( target ); t := i^target; perm := FGA_TiToPQ( i, P, Q ); word2 := (perm^homrep)^(t-i) * word2; target := target * (perm^homperm)^(i-t); od; return word1*word2; end ); InstallGlobalFunction( FGA_CurryAutToPQOU, function( p, q, o, u) return function( aut ) local fg, words, wh; fg := Source( aut ); words := List( GeneratorsOfGroup( fg ), gen -> gen ^ aut ); wh := FGA_WhiteheadAutomorphisms( fg ); # use Nielsen generators only wh := Filtered( wh, f -> FGA_WhiteheadParams(f).isnielsen ); wh := Concatenation( wh, List( wh, Inverse )); return FGA_WhiteheadAnalyse( wh, words, OnTuples, l -> Sum( l, Length ), One( p ), function( v, w ) return FGA_WhiteheadToPQOU( Inverse(w), p, q, o, u ) * v; end, function( v, e ) e := List( e, g -> LetterRepAssocWord(g)[1] ); return FGA_ExtSymListRepToPQO( e, p, q, o ) * v; end ); end; end ); fga/lib/Whitehd.gd0000644000371700037170000000137513275267465015530 0ustar gap-jenkinsgap-jenkins############################################################################# ## #W Whitehd.gd FGA package Christian Sievers ## ## Declarations for computations with Whitehead automorphisms ## #Y 2004 - 2012 ## DeclareAttribute( "FGA_WhiteheadParams", IsGroupHomomorphism ); DeclareAttribute( "FGA_WhiteheadAutomorphisms", IsFreeGroup ); DeclareAttribute( "FGA_NielsenAutomorphisms", IsFreeGroup ); DeclareGlobalFunction( "FGA_WhiteheadAutomorphism" ); DeclareGlobalFunction( "FGA_WhiteheadAnalyse" ); DeclareGlobalFunction( "FGA_WhiteheadToPQOU" ); DeclareGlobalFunction( "FGA_NikToPQ" ); DeclareGlobalFunction( "FGA_TiToPQ" ); DeclareGlobalFunction( "FGA_ExtSymListRepToPQO" ); DeclareGlobalFunction( "FGA_CurryAutToPQOU" ); fga/tst/FGA.tst0000644000371700037170000000432513275267465015013 0ustar gap-jenkinsgap-jenkinsgap> START_TEST("Test of FreeGroups package"); gap> f:=FreeGroup(2); gap> g:=Group(f.1*f.2*f.1); Group([ f1*f2*f1 ]) gap> f.1*f.2 in g; false gap> f.2 in g; false gap> f.1*f.2*f.1 in g; true gap> Rank(g); 1 gap> RepresentativeAction(f,f.1*f.2,f.2*f.1); f1 gap> RepresentativeAction(g,f.1*f.2,f.2*f.1); f1*f2*f1 gap> RepresentativeAction(g,f.2*f.1,f.1*f.2); f1^-1*f2^-1*f1^-1 gap> RepresentativeAction(Group(f.1*f.2),f.1*f.2,f.2*f.1); fail gap> # bug reportet by Ignat Soroko, example slightly modified gap> a:=f.1;; b:=f.2;; gap> g := Group( a^b, a^(b^-1), b^4 );; gap> h := Group( b^2, a^b, a*b*a );; gap> IsConjugate(f,g,h); false gap> f:=FreeGroup(3); gap> e:=Enumerator(f); > gap> g:=Group(List(e{[2..187]},g->g^2));; gap> FreeGeneratorsOfGroup(g); [ f1^2, f2*f1*f2^-1*f1^-1, f2^2, f3*f1*f3^-1*f1^-1, f3*f2*f3^-1*f2^-1, f3^2, f1*f2*f1*f2^-1, f1*f2^2*f1^-1, f1*f3*f1*f3^-1, f1*f3*f2*f3^-1*f2^-1*f1^-1, f1*f3^2*f1^-1, f2*f3*f1*f3^-1*f2^-1*f1^-1, f2*f3*f2*f3^-1, f2*f3^2*f2^-1, f1*f2*f3*f1*f3^-1*f2^-1, f1*f2*f3*f2*f3^-1*f1^-1, f1*f2*f3^2*f2^-1*f1^-1 ] gap> Index(f,g); 8 gap> n:=Normalizer(f,g); Group() gap> Rank(n); 3 gap> g:=Group((f.1*f.2)^5);; gap> FreeGeneratorsOfGroup(Normalizer(f,g^f.3)); [ f3^-1*f1*f2*f3 ] gap> RepresentativeAction(f,g^f.3,g^(f.2*f.3)); f3^-1*f2*f3 gap> Centralizer(f,g); Group([ f1*f2 ]) gap> Centralizer(f,g^f.3); Group([ f3^-1*f1*f2*f3 ]) gap> Centralizer(g,Group((f.1*f.2)^2)); Group([ (f1*f2)^5 ]) gap> g1:=Group((f.1*f.2)^15);; gap> Index(g,g1); 3 gap> RankOfFreeGroup(Intersection(Group(f.2^f.1,f.1^2),Group(f.2,f.1*f.2*f.1^2,f.1^2*f.2*f.1,f.1^3))); 4 gap> # bug #122 gap> f:=FreeGroup(2);; gap> iso := GroupHomomorphismByImages(f,f,[f.1*f.2,f.1*f.2^2],[f.2^2*f.1,f.2*f.1]);; gap> SetIsSurjective(iso,true); gap> Image(iso,PreImagesRepresentative(iso,f.1)); f1 gap> # bug with trivial image / preimage gap> F:=FreeGroup(0);; gap> homFree:=GroupHomomorphismByImages(F, F, [], []); [ ] -> [ ] gap> PreImagesRepresentative(homFree, One(F)); gap> STOP_TEST( "FGA.tst", 100000); fga/tst/testall.g0000664000371700037170000000016513275267465015502 0ustar gap-jenkinsgap-jenkinsLoadPackage("FGA"); TestDirectory(DirectoriesPackageLibrary("FGA", "tst"), rec(exitGAP := true)); FORCE_QUIT_GAP(1); fga/doc/manual.tex0000664000371700037170000000507713275267465015623 0ustar gap-jenkinsgap-jenkins%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %W manual.tex FGA documentation Christian Sievers %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F gapmacro . . . . . . . . . . . . . . . . . read the GAP macro package %% \input GAPROOT/doc/gapmacro \Package{FGA} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F BeginningOfBook . . . . . . . . . . . . . . . . . . . start the book %% \BeginningOfBook{FGA} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F UseReferences . . . . . . . . . . . . . . . . . . specify references %% \UseReferences{GAPROOT/doc/ref} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F TitlePage . . . . . . . . . . . . . . . . . . . . . . nice title page %% \TitlePage{ \centerline{\titlefont FGA}\bigskip \centerline{\subtitlefont Free Group Algorithms} \bigskip\bigskip\bigskip \centerline{\subtitlefont A GAP4 Package}\bigskip\bigskip \centerline{\secfont Version 1.4.0} \vfill \centerline{\secfont by}\vfill \centerline{\secfont Christian Sievers}\medskip % \centerline{Fachbereich Mathematik und Informatik} % \centerline{Institut Computational Mathematics} % \medskip % \centerline{TU Braunschweig}\medskip % \centerline{Pockelsstr. 14} % \centerline{D-38106 Braunschweig} % \medskip % \centerline{email: c.sievers@tu-bs.de} \vfill \centerline{\secfont{\Month} \Year} } % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F TableOfContents . . . . . . . . . . . . generate a table of contents %% \OneColumnTableOfContents %since it's very short %\TableOfContents %use instead if ToC is longer than a column % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F FrontMatter %% \FrontMatter % \immediate\write\citeout{\bs bibdata{./manual,GAPROOT/doc/manualbib.xml.bib}} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F Chapters %% \Chapters \Input{intro} \Input{FGA} \Input{install} % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F Appendices %% \Appendices %\Input{hints} \Bibliography \Index % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %F EndOfBook . . . . . . . . . . . . . . . . . . . . . . . . . that's it %% \EndOfBook % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %E manual.tex . . . . . . . . . . . . . . . . . . . . . . . . ends here fga/doc/intro.tex0000644000371700037170000001206613275267465015473 0ustar gap-jenkinsgap-jenkins%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %W intro.tex FGA documentation Christian Sievers %% %Y 2003 - 2012 %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Chapter{Introduction} \atindex{FGA}{@{\FGA}|indexit} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Overview} This manual describes the {\FGA} (*Free Group Algorithms*) package, a {\GAP} package for computations with finitely generated subgroups of free groups. This package allows you to (constructively) test membership and conjugacy, and to compute free generators, the rank, the index, normalizers, centralizers, and intersections where the groups involved are finitely generated subgroups of free groups. % In addition, it provides generators and a finite presentation for the automorphism group of a finitely generated free group and allows to write any such automorphism as word in these generators. See Chapter "Functionality of the FGA Package" for details. Chapter "Installing and Loading the FGA Package" explains how to install and load the {\FGA} package. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Implementation and background} The methods which are used work mainly with inverse finite automata, a variation of an idea known from theoretical computer science. An inverse finite automaton is a finite state automaton over a symmetric alphabet, i.e. one in which every letter has an inverse, such that each transition between two states for a letter corresponds to a transition in the opposite direction for the inverse letter. Most of these techniques are described in Chapter 4 of \cite{Sims94}, where the same concept is called coset automaton. The method to obtain this automaton is called basic coset enumeration, and in fact it is coset enumeration where only important cosets are defined. Here a coset is called important when there are words and such that is reduced and denotes an element of and denotes an element of . In \cite{BirgetEtAl00}, the connection between finitely generated subgroups of free groups and inverse finite automata is used to transfer results about the space complexity of problems concerning inverse finite automata to analogous results about finitely generated subgroups of free groups. Chapter 6 of \cite{Sims94} describes the Reidemeister-Schreier procedure and a variant called extended coset enumeration which yields a presentation in the given generators. The {\FGA} package uses a variation thereof for its constructive membership test: it leaves out the part of the algorithm that fills in relations and interprets the resulting extended coset table differently. This algorithm might be called extended basic coset enumeration. Some word oriented algorithms in the {\FGA} package use basic facts about free groups. These can, for example, be found in \cite{LyndonSchupp77}. The presentation of the automorphism groups follows \cite{Neumann33}. The algorithm for writing an automorphism in the generators works first at the level of Nielsen generators and uses relations from \cite{Nielsen}. The theoretical background for most of this implementation is explained in \cite{Sievers03}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Integration of the package} The {\FGA} package mainly installs new methods for operations that are already known to {\GAP}. They overlap with methods in the {\GAP} library in the case of groups of finite index. In this case, {\GAP}s methods are usually faster, and the {\FGA} package tries to recognize such cases and to refer to {\GAP}. The methods of the {\FGA} package will only be selected when the groups involved know they are finitely generated. This may not always be the case for groups that were not created by methods of the {\FGA} package. In such a case you will get a `no method found' error, or {\GAP} may try a coset enumeration that stops with the message `the coset enumeration has defined more than 256000 cosets'. You may then call `GeneratorsOfGroup', and try again. Please inform the package author if you observe any remaining problems. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{License} Like the {\GAP} system itself, the {\FGA} package 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 package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You can find the GNU General Public License in the file `COPYING' of the {\FGA} package, and also in the file `GPL' in the `etc' directory of the main {\GAP} distribution, or see \URL{http://www.gnu.org/licenses/gpl.html}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %E fga/doc/FGA.tex0000644000371700037170000002260413275267465014734 0ustar gap-jenkinsgap-jenkins%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %W FGA.tex FGA documentation Christian Sievers %% %Y 2003 - 2016 %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Chapter{Functionality of the FGA package} \atindex{Functionality of the FGA package}{@Functionality % of the {\FGA} package|indexit} This chapter describes methods available from the {\FGA} package. In the following, let be a free group created by `FreeGroup()', and let , and be finitely generated subgroups of created by `Group' or `Subgroup', or computed from some other subgroup of . Let be an element of . For example: \beginexample gap> f := FreeGroup( 2 ); gap> u := Group( f.1^2, f.2^2, f.1*f.2 ); Group([ f1^2, f2^2, f1*f2 ]) gap> u1 := Subgroup( u, [f.1^2, f.1^4*f.2^6] ); Group([ f1^2, f1^4*f2^6 ]) gap> elm := f.1; f1 gap> u2 := Normalizer( u, elm ); Group([ f1^2 ]) \endexample %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{New operations for free groups} These new operations are available for finitely generated subgroups of free groups: \>FreeGeneratorsOfGroup( ) A returns a list of free generators of the finitely generated subgroup of a free group. The elements in this list form an N-reduced set. In addition to being a free (and thus minimal) generating set for , this means that whenever , and are elements or inverses of elements of this list, then \beginlist%unordered \item{--} $\neq1$ implies $||\geq\max(||, ||)$, and \item{--} $\neq1$ and $\neq1$ implies $|| > || - || + ||$ \endlist hold, where $|.|$ denotes the word length. \>RankOfFreeGroup( ) A \>Rank( ) O returns the rank of the finitely generated subgroup of a free group. \>CyclicallyReducedWord( ) O returns the cyclically reduced form of . %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Method installations} This section lists operations that are already known to {\GAP}. {\FGA} installs new methods for them so that they can also be used with free groups. In cases where {\FGA} installs methods that are usually only used internally, user functions are shown instead. \>Normalizer( , ) O \>Normalizer( , ) O The first variant returns the normalizer of the finitely generated subgroup in . The second variant returns the normalizer of $\langle \rangle$ in the finitely generated subgroup (see "ref:Normalizer" in the Reference Manual). \>RepresentativeAction( , , ) O \>IsConjugate( , , ) O `RepresentativeAction' returns an element $ \in $, where is a finitely generated subgroup of a free group, such that $^{}=$, or fail, if no such exists. and may be elements or subgroups of . `IsConjugate' returns a boolean indicating whether such an element exists. \>Centralizer( , ) O \>Centralizer( , ) O returns the centralizer of or in the finitely generated subgroup of a free group. \>Index( , ) O \>IndexNC( , ) O return the index of in , where and are finitely generated subgroups of a free group. The first variant returns fail if is not a subgroup of , the second may return anything in this case. \>Intersection( , \dots ) F returns the intersection of and , where and are finitely generated subgroups of a free group. \>` in '{in} O tests whether is contained in the finitely generated subgroup of a free group. \>IsSubgroup( , ) F tests whether is a subgroup of , where and are finitely generated subgroups of a free group. \>` = '{equality} O test whether the two finitely generated subgroups and of a free group are equal. \>MinimalGeneratingSet( ) A \>SmallGeneratingSet( ) A \>GeneratorsOfGroup( ) A return generating sets for the finitely generated subgroup of a free group. `MinimalGeneratingSet' and `SmallGeneratingSet' return the same free generators as `FreeGeneratorsOfGroup', which are in fact a minimal generating set. `GeneratorsOfGroup' also returns these generators, if no other generators were stored at creation time. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Constructive membership test} It is not only possible to test whether an element is in a finitely generated subgroup of free group, this can also be done constructively. The idiomatic way to do so is by using a homomorphism. Here is an example that computes how to write `f.1^2' in the generators `a=f1^2*f2^2' and `b=f.1^2*f.2', checks the result, and then tries to write `f.1' in the same generators: \beginexample gap> f := FreeGroup( 2 ); gap> ua := f.1^2*f.2^2;; ub := f.1^2*f.2;; gap> u := Group( ua, ub );; gap> g := FreeGroup( "a", "b" );; gap> hom := GroupHomomorphismByImages( g, u, > GeneratorsOfGroup(g), > GeneratorsOfGroup(u) ); [ a, b ] -> [ f1^2*f2^2, f1^2*f2 ] gap> # how can f.1^2 be expressed? gap> PreImagesRepresentative( hom, f.1^2 ); b*a^-1*b gap> last ^ hom; # check this f1^2 gap> ub * ua^-1 * ub; # another check f1^2 gap> PreImagesRepresentative( hom, f.1 ); # try f.1 fail gap> f.1 in u; false \endexample There are also lower level operations to get the same results. \>AsWordLetterRepInGenerators( , ) O \>AsWordLetterRepInFreeGenerators( , ) O return a letter representation (see Section~"ref:Representations for Associative Words" in the {\GAP} Reference Manual) of the given relative to the generators the group was created with or the free generators as returned by `FreeGeneratorsOfGroup'. Continuing the above example: \beginexample gap> AsWordLetterRepInGenerators( f.1^2, u ); [ 2, -1, 2 ] gap> AsWordLetterRepInFreeGenerators( f.1^2, u ); [ 2 ] \endexample This means: to get `f.1^2', multiply the second of the given generators with the inverse of the first and again with the second; or just take the second free generator. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Automorphism groups of free groups} The {\FGA} package knows presentations of the automorphism groups of free groups. It also allows to express an automorphism as word in the generators of these presentations. This sections repeats the {\GAP} standard methods to do so and shows functions to obtain the generating automorphisms. \>AutomorphismGroup( ) A returns the automorphism group of the finitely generated subgroup of a free group. Only a few methods will work with this group. But there is a way to obtain an isomorphic finitely presented group: \>IsomorphismFpGroup( ) A returns an isomorphism of to a finitely presented group. For automorphism groups of free groups, the {\FGA} package implements the presentations of \cite{Neumann33}. The finitely presented group itself can then be obtained with the command `Range'. Here is an example: \beginexample gap> f := FreeGroup( 2 );; gap> a := AutomorphismGroup( f );; gap> iso := IsomorphismFpGroup( a );; gap> Range( iso ); \endexample To express an automorphism as word in the generators of the presentation, just apply the isomorphism obtained from `IsomorphismFpGroup'. \beginexample gap> aut := GroupHomomorphismByImages( f, f, > GeneratorsOfGroup( f ), [ f.1^f.2, f.1*f.2 ] ); [ f1, f2 ] -> [ f2^-1*f1*f2, f1*f2 ] gap> ImageElm( iso, aut ); O^2*U*O*P^-1*U \endexample It is also possible to use `aut^iso' or `Image( iso, aut )'. Using `Image' will perform additional checks on the arguments. The {\FGA} package provides a simpler way to create endomorphisms: \>FreeGroupEndomorphismByImages( , ) F returns the endomorphism that maps the free generators of the finitely generated subgroup of a free group to the elements listed in . You may then apply `IsBijective' to check whether it is an automorphism. The follwowing functions return automorphisms that correspond to the generators in the presentation: \>FreeGroupAutomorphismsGeneratorO( ) F \>FreeGroupAutomorphismsGeneratorP( ) F \>FreeGroupAutomorphismsGeneratorU( ) F \>FreeGroupAutomorphismsGeneratorS( ) F \>FreeGroupAutomorphismsGeneratorT( ) F \>FreeGroupAutomorphismsGeneratorQ( ) F \>FreeGroupAutomorphismsGeneratorR( ) F return the automorphism which maps the free generators [$ x_1, x_2, \dots, x_n $] of to \beginlist \item{O:} [$ x_1^{-1}, x_2, \dots, x_n $] ($n\ge1$) \item{P:} [$ x_2, x_1, x_3, \dots, x_n $] ($n\ge2$) \item{U:} [$ x_1x_2, x_2, x_3, \dots, x_n $] ($n\ge2$) \item{S:} [$ x_2^{-1}, x_3^{-1}, \dots, x_n^{-1}, x_1^{-1} $] ($n\ge1$) \item{T:} [$ x_2, x_1^{-1}, x_3, \dots, x_n $] ($n\ge2$) \item{Q:} [$ x_2, x_3, \dots, x_n, x_1 $] ($n\ge2$) \item{R:} [$ x_2^{-1}, x_1, x_3, x_4, \dots, x_{n-2}, x_nx_{n-1}^{-1}, x_{n-1}^{-1} $] ($n\ge4$) \endlist %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %E fga/doc/install.tex0000664000371700037170000000412713275267465016007 0ustar gap-jenkinsgap-jenkins%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %W install.tex GAP documentation Christian Sievers %% %Y 2003 - 2018 %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Chapter{Installing and loading the FGA package} \atindex{Installing and loading the FGA package}{@Installing % and loading the {\FGA} package|indexit} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Installing the FGA package}\null \atindex{Installing the FGA package}{@Installing % the {\FGA} package|indexit} The installation of the {\FGA} package follows standard {\GAP} rules. So the standard method is to unpack the archive into the `pkg' directory of your {\GAP} distribution. This will create an `fga' subdirectory. For other non-standard options please see Chapter~"ref:Installing a GAP Package" in the {\GAP} Reference Manual. %To create the documentation, go into the `doc' directory and type %`make_doc'. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \Section{Loading the FGA package}\null \atindex{Loading the FGA package}{@loading the {\FGA} package|indexit} The {\FGA} package is configured to autoload, so its functionality is usually available once {\GAP} is started. If {\GAP} does not autoload, you can request the package with the `LoadPackage' command like this: \testexamplefalse% \beginexample gap> LoadPackage( "fga" ); ----------------------------------------------------------------------------- Loading FGA 1.4.0 (Free Group Algorithms) by Christian Sievers (c.sievers@tu-bs.de). Homepage: http://www.icm.tu-bs.de/ag_algebra/software/FGA/ ----------------------------------------------------------------------------- true \endexample You will not see the banner if {\FGA} has already been loaded. The `LoadPackage' command and ways to disable autoloading are described in Section~"ref:Loading a GAP Package" in the {\GAP} Reference Manual. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %E fga/doc/manual.bib0000644000371700037170000000217213275267465015546 0ustar gap-jenkinsgap-jenkins@article{Neumann33, author = {Bernd Neumann}, title = {Die {A}utomorphismengruppe der freien {G}ruppen}, journal = {Math. Annalen}, volume = 107, year = 1933, pages = {367--386} } @article{BirgetEtAl00, author = {J.-C. Birget and S. Margolis and J. Meakin and P. Weil}, title = {{PSPACE}-complete problems for subgroups of free groups and inverse finite automata}, journal = {Theoretical Computer Science}, volume = 242, year = 2000, pages = {247--281} } @book{LyndonSchupp77, author = {Roger C. Lyndon and Paul E. Schupp}, title = {Combinatorial Group Theory}, publisher = {Springer}, year = 1977 }, @mastersthesis{Sievers03, author = {Christian Sievers}, title = {Algorithmen f\accent127ur freie {G}ruppen}, school = {TU Braunschweig}, year = 2003, type = {Diplomarbeit} } @article{Nielsen, author = {J. Nielsen}, title = {Die {I}somorphismengruppe der freien {G}ruppen}, journal = {Math. Annalen}, volume = 91, year = 1924, pages = {169--209} } fga/doc/manual.example-2.tst0000644000371700037170000000244413275267465017417 0ustar gap-jenkinsgap-jenkinsgap> f := FreeGroup( 2 ); gap> u := Group( f.1^2, f.2^2, f.1*f.2 ); Group([ f1^2, f2^2, f1*f2 ]) gap> u1 := Subgroup( u, [f.1^2, f.1^4*f.2^6] ); Group([ f1^2, f1^4*f2^6 ]) gap> elm := f.1; f1 gap> u2 := Normalizer( u, elm ); Group([ f1^2 ]) gap> f := FreeGroup( 2 ); gap> ua := f.1^2*f.2^2;; ub := f.1^2*f.2;; gap> u := Group( ua, ub );; gap> g := FreeGroup( "a", "b" );; gap> hom := GroupHomomorphismByImages( g, u, > GeneratorsOfGroup(g), > GeneratorsOfGroup(u) ); [ a, b ] -> [ f1^2*f2^2, f1^2*f2 ] gap> # how can f.1^2 be expressed? gap> PreImagesRepresentative( hom, f.1^2 ); b*a^-1*b gap> last ^ hom; # check this f1^2 gap> ub * ua^-1 * ub; # another check f1^2 gap> PreImagesRepresentative( hom, f.1 ); # try f.1 fail gap> f.1 in u; false gap> AsWordLetterRepInGenerators( f.1^2, u ); [ 2, -1, 2 ] gap> AsWordLetterRepInFreeGenerators( f.1^2, u ); [ 2 ] gap> f := FreeGroup( 2 );; gap> a := AutomorphismGroup( f );; gap> iso := IsomorphismFpGroup( a );; gap> Range( iso ); gap> aut := GroupHomomorphismByImages( f, f, > GeneratorsOfGroup( f ), [ f.1^f.2, f.1*f.2 ] ); [ f1, f2 ] -> [ f2^-1*f1*f2, f1*f2 ] gap> ImageElm( iso, aut ); O^2*U*O*P^-1*U fga/htm/indxF.htm0000664000371700037170000000277713275267465015435 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index F

FGA : a GAP 4 package - Index F

_ A C E F G I L M N O R S

FreeGeneratorsOfGroup 2.1.1
FreeGroupAutomorphismsGeneratorO 2.4.4
FreeGroupAutomorphismsGeneratorP 2.4.4
FreeGroupAutomorphismsGeneratorQ 2.4.4
FreeGroupAutomorphismsGeneratorR 2.4.4
FreeGroupAutomorphismsGeneratorS 2.4.4
FreeGroupAutomorphismsGeneratorT 2.4.4
FreeGroupAutomorphismsGeneratorU 2.4.4
FreeGroupEndomorphismByImages 2.4.3
Functionality of the FGA package 2.0
Functionality of the FGA package 2.0

[Up]

FGA manual
März 2018
fga/htm/indxN.htm0000664000371700037170000000146613275267465015437 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index N

FGA : a GAP 4 package - Index N

_ A C E F G I L M N O R S

New operations for free groups 2.1
Normalizer 2.2.1

[Up]

FGA manual
März 2018
fga/htm/indxG.htm0000664000371700037170000000136313275267465015424 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index G

FGA : a GAP 4 package - Index G

_ A C E F G I L M N O R S

GeneratorsOfGroup 2.2.9

[Up]

FGA manual
März 2018
fga/htm/theindex.htm0000664000371700037170000000126213275267465016161 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index _

FGA : a GAP 4 package - Index _

_ A C E F G I L M N O R S

[Up]

FGA manual
März 2018
fga/htm/indxO.htm0000664000371700037170000000134613275267465015435 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index O

FGA : a GAP 4 package - Index O

_ A C E F G I L M N O R S

Overview 1.1

[Up]

FGA manual
März 2018
fga/htm/indxM.htm0000664000371700037170000000146613275267465015436 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index M

FGA : a GAP 4 package - Index M

_ A C E F G I L M N O R S

Method installations 2.2
MinimalGeneratingSet 2.2.9

[Up]

FGA manual
März 2018
fga/htm/CHAP001.htm0000664000371700037170000001501613275267465015307 0ustar gap-jenkinsgap-jenkins[FGA] 1 Introduction [Up] [Next] [Index]

1 Introduction

Sections

  1. Overview
  2. Implementation and background
  3. Integration of the package
  4. License

1.1 Overview

This manual describes the FGA (Free Group Algorithms) package, a GAP package for computations with finitely generated subgroups of free groups.

This package allows you to (constructively) test membership and conjugacy, and to compute free generators, the rank, the index, normalizers, centralizers, and intersections where the groups involved are finitely generated subgroups of free groups. In addition, it provides generators and a finite presentation for the automorphism group of a finitely generated free group and allows to write any such automorphism as word in these generators.

See Chapter Functionality of the FGA Package for details.

Chapter Installing and Loading the FGA Package explains how to install and load the FGA package.

1.2 Implementation and background

The methods which are used work mainly with inverse finite automata, a variation of an idea known from theoretical computer science. An inverse finite automaton is a finite state automaton over a symmetric alphabet, i.e. one in which every letter has an inverse, such that each transition between two states for a letter corresponds to a transition in the opposite direction for the inverse letter.

Most of these techniques are described in Chapter 4 of Sims94, where the same concept is called coset automaton. The method to obtain this automaton is called basic coset enumeration, and in fact it is coset enumeration where only important cosets are defined. Here a coset Gg is called important when there are words w and v such that wv is reduced and denotes an element of G and w denotes an element of Gg.

In BirgetEtAl00, the connection between finitely generated subgroups of free groups and inverse finite automata is used to transfer results about the space complexity of problems concerning inverse finite automata to analogous results about finitely generated subgroups of free groups.

Chapter 6 of Sims94 describes the Reidemeister-Schreier procedure and a variant called extended coset enumeration which yields a presentation in the given generators. The FGA package uses a variation thereof for its constructive membership test: it leaves out the part of the algorithm that fills in relations and interprets the resulting extended coset table differently. This algorithm might be called extended basic coset enumeration.

Some word oriented algorithms in the FGA package use basic facts about free groups. These can, for example, be found in LyndonSchupp77.

The presentation of the automorphism groups follows Neumann33. The algorithm for writing an automorphism in the generators works first at the level of Nielsen generators and uses relations from Nielsen.

The theoretical background for most of this implementation is explained in Sievers03.

1.3 Integration of the package

The FGA package mainly installs new methods for operations that are already known to GAP. They overlap with methods in the GAP library in the case of groups of finite index. In this case, GAPs methods are usually faster, and the FGA package tries to recognize such cases and to refer to GAP.

The methods of the FGA package will only be selected when the groups involved know they are finitely generated. This may not always be the case for groups that were not created by methods of the FGA package. In such a case you will get a no method found error, or GAP may try a coset enumeration that stops with the message the coset enumeration has defined more than 256000 cosets. You may then call GeneratorsOfGroup, and try again.

Please inform the package author if you observe any remaining problems.

1.4 License

Like the GAP system itself, the FGA package 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 package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You can find the GNU General Public License in the file COPYING of the FGA package, and also in the file GPL in the etc directory of the main GAP distribution, or see http://www.gnu.org/licenses/gpl.html.

[Up] [Next] [Index]

FGA manual
März 2018
fga/htm/indx_.htm0000664000371700037170000000133413275267465015452 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index _

FGA : a GAP 4 package - Index _

_ A C E F G I L M N O R S

FGA 1.0

[Up]

FGA manual
März 2018
fga/htm/indxS.htm0000664000371700037170000000136413275267465015441 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index S

FGA : a GAP 4 package - Index S

_ A C E F G I L M N O R S

SmallGeneratingSet 2.2.9

[Up]

FGA manual
März 2018
fga/htm/indxI.htm0000664000371700037170000000304013275267465015420 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index I

FGA : a GAP 4 package - Index I

_ A C E F G I L M N O R S

Implementation and background 1.2
in 2.2.6
Index 2.2.4
IndexNC 2.2.4
Installing and loading the FGA package 3.0
Installing and loading the FGA package 3.0
Installing the FGA package 3.1
Installing the FGA package 3.1
Integration of the package 1.3
Intersection 2.2.5
Introduction 1.0
IsConjugate 2.2.2
IsomorphismFpGroup 2.4.2
IsSubgroup 2.2.7

[Up]

FGA manual
März 2018
fga/htm/CHAP002.htm0000664000371700037170000003442013275267465015310 0ustar gap-jenkinsgap-jenkins[FGA] 2 Functionality of the FGA package [Up] [Previous] [Next] [Index]

2 Functionality of the FGA package

Sections

  1. New operations for free groups
  2. Method installations
  3. Constructive membership test
  4. Automorphism groups of free groups

This chapter describes methods available from the FGA package.

In the following, let f be a free group created by FreeGroup(n), and let u, u1 and u2 be finitely generated subgroups of f created by Group or Subgroup, or computed from some other subgroup of f. Let elm be an element of f.

For example:

gap> f := FreeGroup( 2 );                                             
<free group on the generators [ f1, f2 ]>
gap> u := Group( f.1^2, f.2^2, f.1*f.2 );
Group([ f1^2, f2^2, f1*f2 ])
gap> u1 := Subgroup( u, [f.1^2, f.1^4*f.2^6] );
Group([ f1^2, f1^4*f2^6 ])
gap> elm := f.1;
f1
gap> u2 := Normalizer( u, elm );
Group([ f1^2 ])

2.1 New operations for free groups

These new operations are available for finitely generated subgroups of free groups:

  • FreeGeneratorsOfGroup( u ) A

    returns a list of free generators of the finitely generated subgroup u of a free group.

    The elements in this list form an N-reduced set. In addition to being a free (and thus minimal) generating set for u, this means that whenever v1, v2 and v3 are elements or inverses of elements of this list, then

    • v1 v2 ≠ 1 implies |v1 v2 | ≥ max(|v1 |, |v2 |), and
    • v1 v2 ≠ 1 and v2 v3 ≠ 1 implies |v1 v2 v3 | > |v1 | − |v2 | + |v3 |

    hold, where |·| denotes the word length.

  • RankOfFreeGroup( u ) A
  • Rank( u ) O

    returns the rank of the finitely generated subgroup u of a free group.

  • CyclicallyReducedWord( elm ) O

    returns the cyclically reduced form of elm.

    2.2 Method installations

    This section lists operations that are already known to GAP. FGA installs new methods for them so that they can also be used with free groups. In cases where FGA installs methods that are usually only used internally, user functions are shown instead.

  • Normalizer( u1, u2 ) O
  • Normalizer( u, elm ) O

    The first variant returns the normalizer of the finitely generated subgroup u2 in u1.

    The second variant returns the normalizer of 〈elm 〉 in the finitely generated subgroup u (see Normalizer in the Reference Manual).

  • RepresentativeAction( u, d, e ) O
  • IsConjugate( u, d, e ) O

    RepresentativeAction returns an element ru , where u is a finitely generated subgroup of a free group, such that d r =e , or fail, if no such r exists. d and e may be elements or subgroups of u.

    IsConjugate returns a boolean indicating whether such an element r exists.

  • Centralizer( u, u2 ) O
  • Centralizer( u, elm ) O

    returns the centralizer of u2 or elm in the finitely generated subgroup u of a free group.

  • Index( u1, u2 ) O
  • IndexNC( u1, u2 ) O

    return the index of u2 in u1, where u1 and u2 are finitely generated subgroups of a free group. The first variant returns fail if u2 is not a subgroup of u1, the second may return anything in this case.

  • Intersection( u1, u2 ...) F

    returns the intersection of u1 and u2, where u1 and u2 are finitely generated subgroups of a free group.

  • elm in u O

    tests whether elm is contained in the finitely generated subgroup u of a free group.

  • IsSubgroup( u1, u2 ) F

    tests whether u2 is a subgroup of u1, where u1 and u2 are finitely generated subgroups of a free group.

  • u1 = u2 O

    test whether the two finitely generated subgroups u1 and u2 of a free group are equal.

  • MinimalGeneratingSet( u ) A
  • SmallGeneratingSet( u ) A
  • GeneratorsOfGroup( u ) A

    return generating sets for the finitely generated subgroup u of a free group. MinimalGeneratingSet and SmallGeneratingSet return the same free generators as FreeGeneratorsOfGroup, which are in fact a minimal generating set. GeneratorsOfGroup also returns these generators, if no other generators were stored at creation time.

    2.3 Constructive membership test

    It is not only possible to test whether an element is in a finitely generated subgroup of free group, this can also be done constructively. The idiomatic way to do so is by using a homomorphism.

    Here is an example that computes how to write f.1^2 in the generators a=f1^2*f2^2 and b=f.1^2*f.2, checks the result, and then tries to write f.1 in the same generators:

    gap> f := FreeGroup( 2 );
    <free group on the generators [ f1, f2 ]>
    gap> ua := f.1^2*f.2^2;; ub := f.1^2*f.2;;
    gap> u := Group( ua, ub );;
    gap> g := FreeGroup( "a", "b" );;
    gap> hom := GroupHomomorphismByImages( g, u,
    >             GeneratorsOfGroup(g),
    >             GeneratorsOfGroup(u) );
    [ a, b ] -> [ f1^2*f2^2, f1^2*f2 ]
    gap> # how can f.1^2 be expressed?
    gap> PreImagesRepresentative( hom, f.1^2 );
    b*a^-1*b
    gap> last ^ hom; # check this
    f1^2
    gap> ub * ua^-1 * ub; # another check
    f1^2
    gap> PreImagesRepresentative( hom, f.1 ); # try f.1
    fail
    gap> f.1 in u;
    false
    

    There are also lower level operations to get the same results.

  • AsWordLetterRepInGenerators( elm, u ) O
  • AsWordLetterRepInFreeGenerators( elm, u ) O

    return a letter representation (see Section Representations for Associative Words in the GAP Reference Manual) of the given elm relative to the generators the group was created with or the free generators as returned by FreeGeneratorsOfGroup.

    Continuing the above example:

    gap> AsWordLetterRepInGenerators( f.1^2, u );    
    [ 2, -1, 2 ]
    gap> AsWordLetterRepInFreeGenerators( f.1^2, u );
    [ 2 ]
    

    This means: to get f.1^2, multiply the second of the given generators with the inverse of the first and again with the second; or just take the second free generator.

    2.4 Automorphism groups of free groups

    The FGA package knows presentations of the automorphism groups of free groups. It also allows to express an automorphism as word in the generators of these presentations. This sections repeats the GAP standard methods to do so and shows functions to obtain the generating automorphisms.

  • AutomorphismGroup( u ) A

    returns the automorphism group of the finitely generated subgroup u of a free group.

    Only a few methods will work with this group. But there is a way to obtain an isomorphic finitely presented group:

  • IsomorphismFpGroup( group ) A

    returns an isomorphism of group to a finitely presented group. For automorphism groups of free groups, the FGA package implements the presentations of Neumann33. The finitely presented group itself can then be obtained with the command Range.

    Here is an example:

    gap> f := FreeGroup( 2 );;
    gap> a := AutomorphismGroup( f );;
    gap> iso := IsomorphismFpGroup( a );;
    gap> Range( iso );
    <fp group on the generators [ O, P, U ]>
    

    To express an automorphism as word in the generators of the presentation, just apply the isomorphism obtained from IsomorphismFpGroup.

    gap> aut := GroupHomomorphismByImages( f, f,
    >              GeneratorsOfGroup( f ), [ f.1^f.2, f.1*f.2 ] );
    [ f1, f2 ] -> [ f2^-1*f1*f2, f1*f2 ]
    gap> ImageElm( iso, aut );
    O^2*U*O*P^-1*U
    

    It is also possible to use aut^iso or Image( iso, aut ). Using Image will perform additional checks on the arguments.

    The FGA package provides a simpler way to create endomorphisms:

  • FreeGroupEndomorphismByImages( g, imgs ) F

    returns the endomorphism that maps the free generators of the finitely generated subgroup g of a free group to the elements listed in imgs. You may then apply IsBijective to check whether it is an automorphism.

    The follwowing functions return automorphisms that correspond to the generators in the presentation:

  • FreeGroupAutomorphismsGeneratorO( group ) F
  • FreeGroupAutomorphismsGeneratorP( group ) F
  • FreeGroupAutomorphismsGeneratorU( group ) F
  • FreeGroupAutomorphismsGeneratorS( group ) F
  • FreeGroupAutomorphismsGeneratorT( group ) F
  • FreeGroupAutomorphismsGeneratorQ( group ) F
  • FreeGroupAutomorphismsGeneratorR( group ) F

    return the automorphism which maps the free generators [ x1, x2, ..., xn ] of group to

    O:
    [ x1−1, x2, ..., xn ] (n ≥ 1)
    P:
    [ x2, x1, x3, ..., xn ] (n ≥ 2)
    U:
    [ x1x2, x2, x3, ..., xn ] (n ≥ 2)
    S:
    [ x2−1, x3−1, ..., xn−1, x1−1 ] (n ≥ 1)
    T:
    [ x2, x1−1, x3, ..., xn ] (n ≥ 2)
    Q:
    [ x2, x3, ..., xn, x1 ] (n ≥ 2)
    R:
    [ x2−1, x1, x3, x4, ..., xn−2, xnxn−1−1, xn−1−1 ] (n ≥ 4)

    [Up] [Previous] [Next] [Index]

    FGA manual
    März 2018
    fga/htm/indxL.htm0000664000371700037170000000154613275267465015434 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index L

    FGA : a GAP 4 package - Index L

    _ A C E F G I L M N O R S

    License 1.4
    Loading the FGA package 3.2
    loading the FGA package 3.2

    [Up]

    FGA manual
    März 2018
    fga/htm/CHAP003.htm0000664000371700037170000000471213275267465015312 0ustar gap-jenkinsgap-jenkins[FGA] 3 Installing and loading the FGA package [Up] [Previous] [Index]

    3 Installing and loading the FGA package

    Sections

    1. Installing the FGA package
    2. Loading the FGA package

    3.1 Installing the FGA package

    The installation of the FGA package follows standard GAP rules. So the standard method is to unpack the archive into the pkg directory of your GAP distribution. This will create an fga subdirectory.

    For other non-standard options please see Chapter Installing a GAP Package in the GAP Reference Manual.

    3.2 Loading the FGA package

    The FGA package is configured to autoload, so its functionality is usually available once GAP is started.

    If GAP does not autoload, you can request the package with the LoadPackage command like this:

    gap> LoadPackage( "fga" );
    -----------------------------------------------------------------------------
    Loading  FGA 1.4.0 (Free Group Algorithms)
    by Christian Sievers (c.sievers@tu-bs.de).
    Homepage: http://www.icm.tu-bs.de/ag_algebra/software/FGA/
    -----------------------------------------------------------------------------
    true
    

    You will not see the banner if FGA has already been loaded.

    The LoadPackage command and ways to disable autoloading are described in Section Loading a GAP Package in the GAP Reference Manual.

    [Up] [Previous] [Index]

    FGA manual
    März 2018
    fga/htm/chapters.htm0000664000371700037170000000116413275267465016163 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Chapters

    FGA : a GAP 4 package - Chapters

    1. Introduction
    2. Functionality of the FGA package
    3. Installing and loading the FGA package

    FGA manual
    März 2018
    fga/htm/indxA.htm0000664000371700037170000000173313275267465015417 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index A

    FGA : a GAP 4 package - Index A

    _ A C E F G I L M N O R S

    AsWordLetterRepInFreeGenerators 2.3.1
    AsWordLetterRepInGenerators 2.3.1
    Automorphism groups of free groups 2.4
    AutomorphismGroup 2.4.1

    [Up]

    FGA manual
    März 2018
    fga/htm/indxR.htm0000664000371700037170000000155113275267465015436 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index R

    FGA : a GAP 4 package - Index R

    _ A C E F G I L M N O R S

    Rank 2.1.2
    RankOfFreeGroup 2.1.2
    RepresentativeAction 2.2.2

    [Up]

    FGA manual
    März 2018
    fga/htm/indxC.htm0000664000371700037170000000157213275267465015422 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index C

    FGA : a GAP 4 package - Index C

    _ A C E F G I L M N O R S

    Centralizer 2.2.3
    Constructive membership test 2.3
    CyclicallyReducedWord 2.1.3

    [Up]

    FGA manual
    März 2018
    fga/htm/indxE.htm0000664000371700037170000000135213275267465015420 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - Index E

    FGA : a GAP 4 package - Index E

    _ A C E F G I L M N O R S

    equality 2.2.8

    [Up]

    FGA manual
    März 2018
    fga/htm/biblio.htm0000664000371700037170000000300313275267465015604 0ustar gap-jenkinsgap-jenkinsFGA : a GAP 4 package - References

    FGA : a GAP 4 package - References

    [BirgetEtAl00]
    J.-C. Birget, S. Margolis, J. Meakin, and P. Weil.
    PSPACE-complete problems for subgroups of free groups and inverse finite automata.
    Theoretical Computer Science, 242:247--281, 2000.
    [LyndonSchupp77]
    Roger C. Lyndon and Paul E. Schupp.
    Combinatorial Group Theory.
    Springer, 1977.
    [Neumann33]
    Bernd Neumann.
    Die Automorphismengruppe der freien Gruppen.
    Math. Annalen, 107:367--386, 1933.
    [Nielsen]
    J. Nielsen.
    Die Isomorphismengruppe der freien Gruppen.
    Math. Annalen, 91:169--209, 1924.
    [Sievers03]
    Christian Sievers.
    Algorithmen für freie Gruppen.
    Diplomarbeit, TU Braunschweig, 2003.
    [Sims94]
    C. C. Sims.
    Computation with finitely presented groups, volume 48 of Encyclopedia of Mathematics and its Applications.
    Cambridge University Press, Cambridge, 1994.

    [Up]

    FGA manual
    März 2018
    fga/doc/make_doc0000775000371700037170000000234513275267465015307 0ustar gap-jenkinsgap-jenkins#!/bin/sh ############################################################################# ## #W make_doc make FGA Package documentation Christian Sievers ## ## This shell script uses TeX, BibTeX and MakeIndex to build the .dvi, Adobe ## PDF, PostScript (commented out) and HTML (provided you have tth and ## etc/convert.pl) documentation for the FGA Package. ## ## This is nearly identical to Greg Gamble's make_doc to make the ## Example Package documentation. ## set -e [ -L GAPROOT ] || { echo GAPROOT link missing; exit 1; } echo "TeXing documentation" # TeX the manual tex manual # ... and build its bibliography (uncomment if there is a `manual.bib') bibtex manual # TeX the manual again to incorporate the ToC ... and build the index tex manual; GAPROOT/doc/manualindex manual # Finally TeX the manual again to get cross-references right tex manual # Create the PostScript version (uncomment next line, if needed) #dvips -D300 manual -o # Create PDF version pdftex manual; pdftex manual # The HTML version of the manual rm -rf ../htm mkdir ../htm echo "Creating HTML documentation" GAPROOT/etc/convert.pl -t -c -n FGA . ../htm ############################################################################# ## #E fga/doc/manual.toc0000644000371700037170000000126713275267465015603 0ustar gap-jenkinsgap-jenkins\chapcontents {1}{Introduction}{3} \seccontents {1.1}{Overview} {3} \seccontents {1.2}{Implementation and background} {3} \seccontents {1.3}{Integration of the package} {4} \seccontents {1.4}{License} {4} \chapcontents {2}{Functionality of the FGA package}{5} \seccontents {2.1}{New operations for free groups} {5} \seccontents {2.2}{Method installations} {6} \seccontents {2.3}{Constructive membership test} {7} \seccontents {2.4}{Automorphism groups of free groups} {7} \chapcontents {3}{Installing and loading the FGA package}{9} \seccontents {3.1}{Installing the FGA package} {9} \seccontents {3.2}{Loading the FGA package} {9} \chapcontents {}{Bibliography}{10} \chapcontents {}{Index}{11} fga/doc/manual.six0000644000371700037170000000262613275267465015621 0ustar gap-jenkinsgap-jenkinsC intro.tex 1. Introduction I 1.0. FGA S 1.1. Overview S 1.2. Implementation and background S 1.3. Integration of the package S 1.4. License C FGA.tex 2. Functionality of the FGA package I 2.0. Functionality of the FGA package S 2.1. New operations for free groups F 2.1. FreeGeneratorsOfGroup F 2.1. RankOfFreeGroup F 2.1. Rank F 2.1. CyclicallyReducedWord S 2.2. Method installations F 2.2. Normalizer F 2.2. Normalizer F 2.2. RepresentativeAction F 2.2. IsConjugate F 2.2. Centralizer F 2.2. Centralizer F 2.2. Index F 2.2. IndexNC F 2.2. Intersection F 2.2. in F 2.2. IsSubgroup F 2.2. equality F 2.2. MinimalGeneratingSet F 2.2. SmallGeneratingSet F 2.2. GeneratorsOfGroup S 2.3. Constructive membership test F 2.3. AsWordLetterRepInGenerators F 2.3. AsWordLetterRepInFreeGenerators S 2.4. Automorphism groups of free groups F 2.4. AutomorphismGroup F 2.4. IsomorphismFpGroup F 2.4. FreeGroupEndomorphismByImages F 2.4. FreeGroupAutomorphismsGeneratorO F 2.4. FreeGroupAutomorphismsGeneratorP F 2.4. FreeGroupAutomorphismsGeneratorU F 2.4. FreeGroupAutomorphismsGeneratorS F 2.4. FreeGroupAutomorphismsGeneratorT F 2.4. FreeGroupAutomorphismsGeneratorQ F 2.4. FreeGroupAutomorphismsGeneratorR C install.tex 3. Installing and loading the FGA package I 3.0. Installing and loading the FGA package S 3.1. Installing the FGA package I 3.1. Installing the FGA package S 3.2. Loading the FGA package I 3.2. Loading the FGA package fga/doc/manual.mst0000644000371700037170000000046413275267465015617 0ustar gap-jenkinsgap-jenkinspreamble "" postamble "\n" group_skip "\n" headings_flag 1 heading_prefix "\\letter " numhead_positive "{}" symhead_positive "{}" item_0 "\n " item_1 "\n \\sub " item_01 "\n \\sub " item_x1 ", " item_2 "\n \\subsub " item_12 "\n \\subsub " item_x2 ", " page_compositor "--" line_max 1000 fga/doc/manual.pdf0000664000371700037170000042277413275267465015603 0ustar gap-jenkinsgap-jenkins%PDF-1.5 % 3 0 obj << /Length 258 /Filter /FlateDecode >> stream xEMK096I&* ,XmҮ$x }yg.b0 1E@^8F@G}nH1B$6YY( `|ܴsKE>Yۼy<KA;EAkv;fNORC FX N(eԳDqXM,NH46SS2Poq;0y6ې¡gL" mvǼİ1d}uVg\b endstream endobj 28 0 obj << /Length 758 /Filter /FlateDecode >> stream xݘr0~ -ªei:ƻNĖm2+@2̰X|&_/>=( (Jp;@I  cނ_n`%YUǣǏm%1TS+Ix9CVul=vr]R:$+lS&) QgPS 7j^vw4/CRwa#}"ĖvkmIŎBH65/QNӹw0cz>s{k*v G'_qz` a-0IMdNmr)ޯfdxQ >y9&}*͌z^5 Fc֛؇$P0vr'jz̶QsE`s+ endstream endobj 67 0 obj << /Length 2563 /Filter /FlateDecode >> stream xڭˎ>_ m&L&lL9AٶҲHrv>EVh;GX\RYiqM8elx6BE&YAvӰI;x\J;.8.+DZ1dD}QvǒQ[&WQM4sgO͸UwZ=Σ+ښN0 Ki 5.bD&x@aˊH)Nq3=b \:Q\ESe=֯R&p"~@u\J?/I»fˢIof'XcUjR8$h\iF|,y*O Y^FU[Ao7+piЊA_2$R8ᩳ:0 TVFUm3= I$7t90aZPuҞQ "\Ϳ"ZK3'XU}I{=p;"F`qhmS>c-JVxV@ރö rIȹ{~3:IkZY* w/C{iڼ 'f:`,#ˠFQr7F.up <{P+F`'HC8W_an aQɺ-/6+u <0b>'U+néL? 4?jCP/mt o8N @Lm_5{9ϳCTA EVEm/:sB`|x"iyg 8tJ0<5% f<>^䊣PsYԪ e㓱ga?Gt&ʭAz@ǯJdB!hn}dıѼ4=0°.;.`F03]z!4utzҶSAGC.Xs|釩4 V Ǩ08(A;GRvNQI`esp\LR\jJR!OUO+WM[ᬌB+" pY-4&> MDڅɍ.e?o] }o$7N |Ӓrd-}!*dXig0.\jct zhzjSQ].ȣDđz{Jq0'Ja9ŵE,DP` [' Mhgġk#oH 3[uUvu[e,)Ӑ2ݦ!1F2΋bw䊪! xd@:z,X Rf$gՌZ:PקA5(B8@KLx5X*IuE\/QAA5"zkT3h=#ҰM 5h/ ew{En ۠:$6e LŢ/1ݜ%P/lӕ{6k֞&]sO[ hɘBY^6ݶ\AQz"4Mi@S`^DOZ^)A9ZӔqڥry|О8EvLJDXNkYE^Iπ`μkur$$^y Snt%́MՉzHFs[&Xa]nbP|AD̤֧5tIp)Ia,΃\q:+) ԔePIa*?RDѝO$ŠU`ӛ\0eB{GV/ѡdRW!VJpaoJpO6DE5wb2@71@ݏtKdͯe~\gqTSжi^WLw~@8.L ` ?z;aIPPvIZx<ȕ77ߦ=)O 'DDI0oLDڭgm2Vvi'MkM#_Я\ ":$1g}pA ` endstream endobj 81 0 obj << /Length 1714 /Filter /FlateDecode >> stream xڕX_oH OctfnOT 5$( qBxm&VXā ԃ0rE䆃b 2^G p IjlkSGڗrNIM<3j+ M w8`Veb?0r%=!ḃZ:oPIg5as.IЯ֚6!#"Iqvܣ VvKV`jgyv@uҼ,h%7C;{Zژz],xeY-zD%!$+M8-/Μ\#OQBzã|})?̒-z@hFJuRG AϺ72gl,Iy̓& \??czL0~˓= 퍂 |hۗ솗exZ:I;ē\_W{$^ڗ endstream endobj 94 0 obj << /Length 1699 /Filter /FlateDecode >> stream xXI6WhcȤ MH@YM/, $y&_G$^ҙC.6%=/T2INhIMFRkh}ɧٟHI!IG!Ť|lSOq/T"JhH2~]M:P&ݿw*$ھ ( f8#(HѠÇ$b8"8vIP`uE9%ZP ZP4;zVM|SgSU'HJEe Fҧ&!NWъNlb5Z y.hi$ASufw=][nDÕ@ u*^oW*)x(rmc άlM^,!]^}sO5[X`F1*y1 eKNuvV#5 ϸp.PՂm⾦^2ܶOy~'Y~zF -^$gDzxȿ<<.|jLl-w>椔NȦۦk E74(UziyH^mǰZ}?z[K[c*?!rӐ?(iv`ׁU@~=}4H0q!(-oRnO5"0Z7eX3TB[%&1jFcWG p]$^R8%x4 p٦7'^.$!j$9JOz9@¾YCqض*{EƛݭnW.TKiiu TF/.]@6/wvo`z4nnE`;1F[}r@$N:|lMږMN}ܭ[;_Ly YW#ὍW cZIeմ㪫>ǃu2{N6֮B3. +_z=]#4.mXc ѱ8e8h`$p($1U}> stream xZK۸W訩AlWrZ--aFJ䄤4$4 EuI_w /FFZRX)RCSky?C>C38&+캼O6T5ETnۢ*C~vMՃ{}n_;׏Ǹi3"iAwO )wiTٺ(6?rK0!n}Lӭ>hZ^=ڏֽjyqM6kX#_HR"_+a0e\,A((T}<8^t u5fgS]Cmk{S\5n4&"$ L=NP8Qmsitݑ ʮu%8&H #Yo4Ѯ  \ºHgƘbf !3:sHVmCOSNHIރz"a{LA0Aw'Z@D1`)$_&1* 6\aD%X(; ĨE.Bz14``LE`B#,5@x{*v3ƴnZ5.7Ԧ= L0,Zs!єWt~|*hQ 6tR鹅Ftw6 0޹c6hTGH1,۶d} ,>!Dj)YH< G, R$$(#*<[XgV:uFF3&td1~[7%d˭1ه{!.sw}zC<զ1e YïULAаT.f]b G0I斂_"7cwovAO`)'a +x)Hlg`0PBD˂uw 4J9v8ݒI_Ą`ys AE/ȁemӘcF6)w>g'f#gIpY&`Q=Ɯd폃8*?t7NߧU pvfg*TЅul\Tgub konL.NZKSs5IU u<(9NoTV&'A8RAk}EiŽnJ;AK&.%e^w+w $7ؑ 7 Ⱦ]nla\A:3fD6#";;@4rq=&=r!K:*S{X{/݂&T0 ŋVW7Y d"yk6>m#2If]T=;K!;B>]dw}HRmw{*ya_ >Q Q*. X$|w9. Y`U7CY}'"A1Bg6;|xrx.'rS8CC٨N&hIѴÁdH8P2ry{=s%;"Գ{2]Sߚ9 _\Sm^ZnsBd9'(Qe|7Q%<6uE ^Ju={vOR1_cc q,:;PO6>*nkEi[?ݿzK endstream endobj 127 0 obj << /Length 1878 /Filter /FlateDecode >> stream xڭXK6WE^جHMm$[H.Chյ%Cl;(&'p3ɏ/p,f=I$If5yM^ӹ|/d8^MM/6ayq]MS 1g"(;A4pdN4s0k _ˢnT%WH|)@8y[p%TREB)8ܓMY) b-YjiK%a,//aQv3lw5!E`HXl#/ oqxǗp^|\8tݨnjSU=u?$ߓ|>KHp+Dx # Z97Y,7g}*ߧ2>‡C׃˗ܨ x8ՌIY[]7Z8yB.#wp1ͻ-"C=~aZN =pL)Bs~xܐIXZ!#MP.`^ح)?r$.:+T e) zF7:tMS}i\z|8yN^js2 ¶ja&Tx%(lT`~U3#dc̲4gJF$HMdIN8 ڙ֘S`֓]4.0aUV<,Y_.A! @k\|Zg l”I6q3Cy,$ @䇳VϿ D,FFp^!J7?֌ (~jJW1abj`vrD &s &Abܗ o]0l[ z2!`omxpG%Sas Sh< P1ѩG}[K²Ԩ51 ˭QXR3fK:ڏ޸0VwFs @%@}c;mcd809h/ K3M2a]@ p}sPG> dgUQJ .יk̽Lt PW3~nQg,Iޘlc!\]xur w9Ty]e7L35R6S!rzAԿL<"TFQ*,lkYWnBCySȂh N~`"n pq`Dccњܨ50aHW1 5 κA4Kdj[ \ٰWͶ\u2.ЇFp7lcZȍQ7FVc7@{וDv5Р)^B:eab٪ʐ;湥w%m 7w#[ۉ'AQ 0G䷛'8o endstream endobj 134 0 obj << /Length 2124 /Filter /FlateDecode >> stream xZ[Ӹ~W1&:Z2bXaegNPe'%SZ+L2KBVՓ\d4j6t Ct~F~ޡJ [ouW1xH/6ISlQ4ةrf&w4_ڇu6Q<?cmS`0\-f_e77崶/{,s;ܴv^;WN.l9AҝS+Gj+e)&wh*UO;b<(p~ T%0cV :Eɔ&HJ5 3aX";%Q`Y+hXb8%X0F\ <†*$k)a?2$m^ja)yT+chXVp;n`$EG@ $ήk١k?ޱcw#t1"ro"qVyw̾rB#V$ApƆ5+ z/ZlwLumnzd@Y 1 $(X8Y>(TsO7n tΈ|؇֒'kuD2l=G[cg{Ҧ38*L^'M6-9Jc+|xrVHq6eyo)4VI3;F?f?rgq GD0WͳX@v3EF>`YnfMgo )%vOrJp̾"/=m֖~,Wv4ajU^eMY.֍v"%ZQ(u)i\;~z`P -SԤ?0[3벮O7nvSli]8FCd/THR;l<“AwgBo)p:-l`'7Skz?X jrV7 oj]K[QP۱>#Y^ g1F6詺+TyָmGx9 ;!UG Ds^ǽ|v=Yk@<r^0O Tw[ҵ {B 5Rاef9P9rBrV,b@{w‚;x7杂 >= !kS2neRx6$D= )_碨}' {WNڵb )QHmSoD4ظ6&LE %ߢ7yG>i?c9SL$&=;a]H1eRh D Ɏ 6BgRE뒻|VjRVjf' ]¯X<翖RET,.% bo;[c)?i'qUZ7=8as |0qR{cp0;!~8 @I׻vNX}|cE@&;%= 6n߱+tq{V~Wr붇)Qչ_XD}t{H"~H(DPpL endstream endobj 5 0 obj << /Type /ObjStm /N 100 /First 820 /Length 1912 /Filter /FlateDecode >> stream xڵY[o~_1h+u@Sy9dim v]ֲeye.`xnߐ!W*uYYbRQ*g)b Vq 0uT0R "rٰ Q͖rVx٫#L&1 QT$ǂJ"ց&Bh!_Gqt{0J6ؑ:'͢nћ Xae%,0g1] SXQ2#z52E'3`̀Cd[('!N#~B0 Zq@2E*c5tt=.~ wtawY:BAh!Z$3 x7jī!EZ3:>)u.J1.rUorLGo^%guʗ,]-AS{ &z|QpokulR 5\5 D^.jP"C 7Msx̶ M&5M6dB jPC*;5 P /6Wrٜ\)b$$I#Hę:TZ/fVǽk&N7S懳4~bVaؑWY֛j_($&͑Y6bj}[$%{#81jVaoU/+u]/,b[xE1A#he^o뉚Vh6k/@ :RѴHDz)k\n .WӃ1V9Fu=j~gq73:!7ǓN\խA6`DoHg;)\ 㵡=;٠sl&8Em圵qjz5ֈ%gFv> 5o_\9fϤ@sw}ѓw|L;nT,x'r[?x'Md7M2MEq 0PǢu1rMlfL?)P֡vQ?NJ6Z@P;C.%6e 5|^Mb|Y,b'!i@ j)j(\">)kktPPD*>M٪YLpdm" wʳ$6WēP" N秨&OAC裬OmG`?|͘_]C'tQ :$>GWciD\dpކ:lzq}1<\( ~k[9nퟩ3wy1ga/Z-_F` Y$ q@aYBPs_8[V9*F뾛=_ɷd͓lUwN3M lCG0l7G[$F-vi+`QLGRu/Yۍ2x@Fbަ>:i6FUݿo{m;~=sIdEe{xSvR` ypӌNzʞw{͞ tيؖ5I>,7B4䮑xzTrW0Fvc_0u3z#r[b5h{+eꐻRfq#X;S? )v endstream endobj 156 0 obj << /Length 1090 /Filter /FlateDecode >> stream xVn6}Wd͋()P4]4i-hRti,#ZikDs93g?n,R j Y,J"K631s'$YR>F(d)RntQr7RʍJoh0!l7XlvpB:;| h388Q%H2F8bPd,L<^-:;(|ގb"*( bV_>ހnlUjOљzęI W^\H{' UQTs.g/rftpq$C{\[x͏ǥ`}di‘DZ\|o9c4$SdAF–K:b(0ـn".$l=LTūjp)*{7ȑ`qvb%GdP:٢Rnu9jp}ӯW1THwnJPr~p˪ wJX]k{}lzYCɖ!{CU.טM(N)<gFve[X/f, ~WZuXSrKmC/U@ppeHpa][ *H"@Dŝ>~<3JA7yEXdv7) a@QO>t7zۃڣ] ݿP.AO^|}ٸzT/}ߴ&D)09.Ӊ@ K;vzQW椝Y@pƵSU3]w<>gPn=#I5g/ֺ,o8zK@Z]܄6&0;tp7Ѷ%Jʔ+V :'$~P x\1uw?M!Y/?OR$}dzYpcEWـqu endstream endobj 162 0 obj << /Length 853 /Filter /FlateDecode >> stream xڭUM01޶eA(Z",uĉSݥ'3x{3;3B`f}F0Ɍp̲.ͦ@0M{p c}DM 3dٌz#rŌB?3̉ $n'WѱT֦ G,al4* OB(G1꩐8/J/f۶j=\uӇs?n>l}XNp2z=8!D9$Fan\^3ؚ!8"H_1 JNfpyьvam2#D܆w3,P2BOLr2PR(Q!}կ Jݵ6KTӾf zٲR?dqiz)_˓Aعv븭N:> stream xڽXKsF W(X<:ˣֱS[hi%1I쪿X"mKLX|ȗ=ʑ/8M=8^Г!{Y8N~0 p/@ B! 91YF`Hя4//"&Z0ل+d^̟uP)*Ua`g̉pMsG\*%5Cc2]Y\M(M2.%$8L맅5~1}} 7܆o4'@7_5F)}`@ffJ?~fEu5*i &u8UtHL.͛B d R@yA ~VY)Bei?cHx)ͬui\Y`8$kGI[)YYk}ircq=8Cym+NȣZQԭJTiJ),¬νKct@ +BMXMiʋou,\q+yNzc)TNKPbD\uZ%E3ED8mN6@ uCl/y/T^8%q;vʴSp>ff:U ʎOT+kJ͉Nb;4G%65fzXE~Υ2u5( DLt]Cq4CѺEN.n1o#!Y3!oY q;a"t6E]p[Iʑ0WKK&#ϯ3ɺuHt [Hq{9lNuMaW*v =$3gS ]SI($ێ~m@w`:Hkv.G uc,GɢUugǂkn;v=paLQ_tM-ʵj5`wM%7pj76)9h%sOma4vu*;GC0Xt9 JvbJur3CLt NVK;.n&| endstream endobj 230 0 obj << /Length1 1436 /Length2 6100 /Length3 0 /Length 7083 /Filter /FlateDecode >> stream xڍwT]6RRJR ݝ "003tH7Jw))%J *R ҡ Z߷f\}Ϻ󖁱 8 P@A PsSp1X )  c`B9@"4HBRQi* p, A;@RRJ.p  Ft8 ~G(`"8uBB` c/@Fp,.J]J8 (;g]ܐ08`GÑ: ? E 3 EH/`puq8~ (?pC_J0?a"/j?f5$LG"0p(ܽ4 @C aveBH\KQb@I I1:]l`ⅆ2.`| ~>h`/(|`w8q+ C@qwt< X=YC!Mb!3u{J|JQY  $@8`ğP zEU/;oc 0u@SgWCU Ə/i P7#<0[6qӋsF (,{eO `mc#ȋ5?TC E.OXL`^Wb~Lap_ "Q8 _h@?. ". 7&& B{ K:^ pO8$ *XvT!<,Kvd!,0\ ף6j`5]CO(gR{=;$nx!If')lŘhNr}1'_]=K%wVd0Hm~6µ@M8x1~d^mmc*in֗сw݃9pj2,̦^[쾑AѸ)I9qXٰŝ)`d>fEO+aW`rىf]WYj{MwpNղzͯ wV".%5>,u?৽ܡVim&ER!""WiW].<={ޮ5Z񞯛(xrz]MQpY8\sAUx}O(% `y(ybw>[9aD/d/M/@½$0da@]MRjp]l^i%GwE]C?D'[x}2.I."ܖ&-+R; \JaZ6hTm%rdRϾdm3͒nn~9G\Vf1+; ܸc~+Rcvy:V?'$s &bLS~_oSv|eն5 {%WI;@`_vbC[P+.cvב=ŵ4&Ч\$gvIfgQoU|M,\7%>!$5/=S9VNyb ރ-d`PQek$tӧ'-)ڱKԛ hTiVY$Q{ͺ+vkFQB|KK 뀌4g%ot^nf-@X|Bb'wڏy'e^lSE} pplΣG _j kp*ME۵4n;jx4|0iaM.(| 3q[ϻk7y&rԧ| &/H>ͫȖZ(?90'xmj$C?ꛑG؂4E8[&eBhągJ6„LswOUx_jj2ZMݍ|~ކ(w1?BչmWk~qDτl̪\4$T,? qRN=s&0k.Y2ӝ5%uۙ[ NFL]5ǂl'%=ъ1RsG%L[pҚZr/2ՆWLCTА72G]*R5.u+h?B㎋c1Q_Zm*C/ӎ铙Ͼ#\,-q;: %TrUS-9n@X#0civ)jc5trdWw eөx/4 s|bҏ=솛*OgEBE؇}UK+-3z\74&LA aBR2}#Zߪ{'q~&$r~o':JEQW)Ty Xò ѱ[g~4^ < 9fAw؎IyV Cvi5txguDx8۾?It-l&/pV [. MA\ACF&㡜S3 w?5a1PoRb{0ؚ2%|a2ww̻U%W9v|wrn5G E5\IyH3Lؚeua]+I")27l@'cXI@(w'{漜u.=c'2JT8pgB/I\^`*ee uz*X6}hFBH|A`d3b^ھ۾SʰP3J"S&wVj&Dl睡`S*]3/,pikC )dq琌(V V{6pƸ+P7* A1>O7JiQ3"DͲ\VN BNMf}BLǖy-6 fmWQϦ%/Rc*IG9 K)uH7+3&gsh0āX@dߌDܹbmڟNm[rzS NkUD((^X'?e\Պ"3?]IIj1SE,bXtFґv\Af&zru/T;ﳵ]jw$Apqi'8+ S1h"NJ5.\(dQYpt<8ia6vղ51)W8M[lB ˀ>x"U:Q*?}_ BÝ#}{^\L]ϡVB3wc@7gtrz:. fX๟Έ◯寮 ju?(sTق )b88#`? ˸ͱjQd~VMO'X]N T C9‗jᐭh~J.63{ӈ1/j|e랰Њ@+lʲPNZlŜ6D4x_){Zjr#53oyɱ<S d8 ~:GP&t(`)C_Dؒ}x20εp=8m69{QQ*V꾢N"$GIQMޗ2aj#7CQM g:Ė:~Nj/t*m+f\{;b3?$X՚$%`SW(ͪ)__2:Iy֚ao-gY&&DB,[} [ȥ0dAFNSkU[*$;h brOXǚVK}2•/j;ktKg{dpGn CdÒ: -̑$2<~KY(In{ۤ]z,8`YViBN+09b譔F%U;2TԟbYsW٫l?Q8^x}Y&: WX)Aٵ*LBQKkfice9)692yO02WF{K`g@arYERca':ʬԕ*~,fž@i˷3ڍ'2>&-A4a='mwژ{rP .(NL:~ :)E~Ҽ-E&򯎄,ܒsS5\KJ%Psh:|,g}8wToFϸ/ +<=N0lfQbB弅jzL܈m}kLG9[{5 XǺP<~|s:9̹6sf&Wnd>>09!IH;gK'$ yC%ʊDS޾T/Kr|E٩41A$D { b|U{탶I2ɛ 19h5v5(ebnWyZd>IN{mD񳈽jK֗_\c$joYQP9z|{}L^qމ]J=̤~I <)[? %?N(YԢBBȗeU,VT>v\v1/zjSWt!`_p/lm~%E/_> vFnRzR& 1J4ni92ccZM.}rKY`OR4Üˮ^F}l r{Y?4U[|󆦏UA~w1.HY4~v 3,'TCR7S&dؘK+6R r\Gq];"><_M|.K*zv;`s$"4*SC/ w9 I_R TCuhCMisyf3 /9S3ձ.L5h"Q&0hv^L;%]izĂ `D4jO>=iTL,N۪PIM2 e!h4ivgbo2-*#fA{Im zo[="Atyqv][ǏIb/ϰ&A☩D.is˨x}iAL>&2PrSߌ%3eOV4Gf0˳4n9B4G_YI#O({g!FSz 7CqnYe|"[>zd{gQ|! hfXCVK[C R ׸\>McL{P<D;W`%Uxc[re+lb~:njItF. ޠҡjv%WlR)b@|Ͳzv!^w0cqʣ^Z$i++#gfTœŽ Vtmzf/D6'T0/?2ؾ%Yr=(qD++w~oѹ[G`Kw.gS' uǾJ_Sp]LiMJckAS,jd[KuV73 2u{c7~P_i0*)ctS!Mm8d"d[I7>J2&ā22X*:#@(c7n*.@aR[OYY3$L|JM}Ks;K>Y@TZ? 4whUP}Xve1S-w**lן?ywC/_ endstream endobj 232 0 obj << /Length1 1429 /Length2 6269 /Length3 0 /Length 7237 /Filter /FlateDecode >> stream xڍtT6!HHĀt)!3034H ()0"Rҍ4;ƽ[֬s}>هXP!hA @E(%4a0 "2XLtp %eR2""QH* h!  uuCc JKK v(CP'0 FAܱ':acG974CFXGB ]y>P !΀_? pLܠ?1FBXuQX/3 0{@:w @Pog ].PB`/"B``( % )rBB=(!D_awVAChɯTHtq]~!l zzA4UR0W !"""%-x Nn¿›y@~`lA H# @!4  ܑgqI C\GB}"X"~^b匀C_auMumSVFE"/IaA cMj]?b_{3Z?"q~RS(/wB /췙0ݡ0hE`TsȟՅ8C۪cA 5BQ /vr?)A Yb[_6h9=>($ jp'H ؝ Ego4-/@$ ;`"}0 ?(/Ű0 GbN^H,[:ج@ '1lʈ7J}W s D6zݼ"3ly̒ϡE懪uɆ? ԓL ~(TzL$hxhG-O7 N|}u`{V W+$I1_Mۄug'D 2Q SbzO/V` tD`EόH;E7PT8i\!K23E3*Fq𚶷޽Mg۟P#i*o@כ\gZ\?g 0BfRsq  L>@>57ؙi t^9DHgmL;9ߟU5-P|(mï%?>+`pSsȌPky;m([  - $-JL|(To[/ */cVfZ(oȶ'ط^ڥ.}伾xTRlG0;+Q~D*"QQf~Rޫ6b;&l5 &Ζ_`4U9 'u;7'm'T ބ(>: l?yk g4ʷMN/഍[b<+y-^ x{6~0qKl휩RیOkw7Poi 3t ƒ/g)&+GTQEܳiWU1F!b?MUpUʡ#?zˇN,6!6uulǚuyovU|Zucg.:}i)Rڛ 9O2fsCNgcweR[hF[7ozv8FJY=of6wTȰrIMύZdfH_wI'#v8(kcV/Cnh;WRZN$_z=+V+E )N칾Dq)/=hNhӘgRQ?46Xh.˺~דMKme.{om$X"O9O;C8>u|*j/4>{*d7&R$Ú zWlu"oyz/4Ϊ)7_uFiկu+֘F8rL ;sH߼ޞ<,rؖk4P͕a1S5V^HPaT珳`IyMXAIDq8/p"M (ZMx.Tc)/6-_I伵k<YY8)X-9wX]Z㻗^<S0%Zkf LAkff sw(iki AF,FkC!'^[[Pu0̩ 31:9%$y\N1#ݒjh'F+U* >\zCFBcw;'ar?aؾ8D́Ildk86޲GIGr;,m!OeR PÇ)5.72g#D}(a#T>W_3oQ r<6|Kӝbc635n8ru/24yW-PAo6e,8<ڶ5`Qwg2KRBuŵ՝iTOȫo_14琲e҅Y3A1zYP@5*4i]qNSLec >JD֤V#!=W vN~M)A6ށvrܞ$} kZuGCQ%yüQN e3p߰p(7jߒwj<"=u4ӆxO;Sp˾%-y>-}I<{~) UX73@EHJRuz"xWsA W=$p/ msXԲ^A;~R>Z>s6I4bR4AsݩPvg=^M!Ƅc: ֆQ:nKK?@RxtPEZjanzt~T]Sk^oG22yMi7N_㊨ 8োZ޹7+CmgpL^ǐOs)JE_0o~]1>8\Z"HCV'"qj^ߙv[ܟv y3;qkr.޲TlUؽ^# pUqrv쮗 r?uKgDCYѬ'[7Mp9P&ir{~3ȬsVk}]P]&v +mfA%;~!z&ї[l.(4Sk% E3C5gC]/ mf^xst Qr/NY饒inX+pߨ{_%aqz'9ZB|ɂ2xOU BUYQÄݗG%>ז5JEb.JaPҐơݭ/[̪G2 S,׍ gJhDj:0mq@zvCEv1؂cǵ;~"om|k-[`7rW::ʠ=oֺǮu'F=y!p`U2Nv6WWO]myCUgCjnFs';G|I4c=_]""M\$zUrڨ,fk1xg| x]GW E}yv-:De 탇7 x?iʔ7TE?NQ+B~>ִ_9x5pj[]B߾5iMKld bZ'ؽ?MeRi]jDSSrW8$+M,)ݙ/y~%zgM!gh4Dl3&F)U,X-j}Ԋ?BxCBr]wBQ>ònCx^ïm3UuuACU]tLI]/^'IJ7h jSst|fxql7̈O*FjF5"yeq1;PQNVV^}GiZ=W;HV_7yw_TۆN%MrAű6o [45F~ 6+l+NvH[̊+w[0# mwRqKxgkgL0$  ҫUTQqLjIoDo9kbC~}yiU!>÷%>4;0"3:B]t얤& kZ̑LOnW|"A64DbSw{-2]{' " zxcfR~YpC MuNLb6T{Y`4*l` o2- q7nUM3&mtsDV;Z2}Z)S@OJkXK^-Vm@\ȁgfs$/3 #gL[,dMM+8q.%֫Q6: oyfok|n0lXlAD8SxCXzK8y)ҎZ Yf_(WE|.䬩rA8&4D>W3l"6S[/T[a|ּx \ N>sFnKڮĠT ]˶y`%̮>ZAg#Ul3xE]9gZz_ i}nu9r{*jpoA[$SڬnU@}1a a?*pj8~93.L^nN4G!3)o"=xK Wl%1uF־oJu)g(twߙT&(5ًJr7R%:?z,+̉괱c 4#]}2Pʮј̓mm9TDpV5UpC苽lQ&kbY>owT(7AmAr*MK$m6mU|mQiΨ xCD1eAזW\ )f]WtZ| =-=&,c"'=,Re/spC5$5yYF]9S3)pkb().FNs<_%l~3$zRdh tԅ͗0*[ٳ.&m5W@Aa,x'?ꌸҝQ<.:9Jk7@hz5 q uT}S&5_dEDQ*͕ ’yF, v+3fwckʐrX^tb^Ow$\:yn, 8 endstream endobj 234 0 obj << /Length1 1550 /Length2 6859 /Length3 0 /Length 7907 /Filter /FlateDecode >> stream xڍT6H{%!zEޛ 7A4E@@s=w왽dQGGi QB"<@^~1)//@bC! X n(!_ y7)&PsPD /7&Py5$"`GxИ}~9@QQYg B4Ah3fG0GaBK8.b|| g/^ C; (d4^ =An!aq`vj] '_` 0Bx( h+iG!1  ~(@ ԇ\(^ F_a0ǬG:;Ch`n0ܽ\{!젿ʰsw3D\! 8?6{ /*,,@\/߯ ] fL .HS`>|Q o+ `{3sn0/9?F~@,1 C"_11ן!<Qa~G"H_b=hOpK Q.-7W7#%w87ap? rј.DbzTc_ ;/aAaQ4/0 bCR_v_! :Hׄxi2f0 A0=}`ݯf@Ƭ@LWA~Nj@1.L(ҍ1yn 3 _?c]?0&C>5c Fs3 b{֢ ?\0rAaFͯ8v V+^?L0?9 k]^N0B렁<*gcWu8]gKoM`k{~\$=z0Qǜ-x2\Gp碫NԦ.PrFʘF~bȼ2 }z<@p \{,75C?K<.T Ƙ74@Mքb:/OM`.v`]i#c-q@н^K>vH{RhV2gz=htf9j;jAx~/%s4T{1/ T De$r:pa¥D*\GCnޯ`&[oۇz"S &YovTޑq* k#9pt:dD&I hlbeh6 &%&w:(BxdHd ʼn {kwt{ݲJu;R4s)bSC?J5&\nəN.]ZXC~Ba.{b-uK퐲SX11^Uc?Ey?H߭gxh~.h=jAG. \Zf/aQw@ !^,h#:\Z}pלIs Ywe^䭵t|j>!Jx~g-[U{iiJقeh$4~fDGHJ`ZNUK9R%՗H5E}opݝگ ItqX^bq~fK4֔ dz Jy_J"Dv0: 2 :~?GswA9\̹tPees:;XizSF;_ؼU=m,5%c]as|__uAJe𛩝'p^MTezV&[!=Z{RJ_+`֘E5CO>u'GWxZƚ;or8.e-)zc]Q9E^b:> 3?dZU+EфVy7/h1Ь] |WbI@~z&RMӺ]d0T:@2ILVՑ`jFchk[$2E#)aʄEߓ|@}#'>JffʥC @OVk^N3'~:zd69|N_v-Na^̙Ut>ř~g>T⻐$j%ʲKnvcĝ"PPj=RYbKP8^$VP8/Em$uΝ`EF6yYۈ;u3)d cjV +#1Df/ #ec=&d 4q ?=#ӋR}#E6c`H¤ô9:@m>2Za4^Jk 6/'ЁX'd}@-Y/SShGv*PtUbK4HT2Q4r+V5yҁtWݣ\̭=ٲʻ+ƏI,w/M>ja,J8ԁw ~_Z-gnE_{|"loGuu36xg׿eHJSՇNpMmVbPF8;*xq6=qD=neCnbUuN\ʄs*ː'ӔEwNT3$/r܉@)x;e}%h7QpWNT$#hBpq3gX8$]eHV_6 I,w2L3_& j(fsCIdn0Zwb/|]g+V?\!EW6hYq"h"V#=$u~ADJek.4sISr5 $Ze(^s²(6bbPqyL2^f MtΙj #0{5iϑޱsZ VФ`pjdn=_ɸ5A]xDFCGѣSW-Z]8p8psdrΰ|.nJPFX=t.!ըa4qMD\=ɭ*/0|^BM},"}ʴ"B._ɞzҨw}}T'!n끸 g |VLUm m*͞zVYϘޥ(HyOYbQl 藋=?+PVq Ъ7oQމ ?2Y޼-1{|[Y8~_6.IBEY٪ttW $ݩ?X: T_4ќ^~WylM̘ZǃpҌ[&$ݎ.5!YQg4(iBQ<3\$9is}*I;&-H--Yl+3G+V[gk+I?HZ*F`+?Z8cor`ڮA?5ǣc|@tZh_!o &.)u0~jI/P/ Ka폼OлÁBdGFu\/Ȋ^Tu_ҋB^Ζ{on I3ȏTv_5}C*4WQb}q^QA52#4tm@ee?r̲O{~\"M31oUG;&2Z?_liVw? 9 ϲAk#21GGmoH̰ΘXlt?];vWI&?a zXjmӖC%M8(T =5iё@؟VUA%j͋?UjH;w*.,6f }u@_BCB#aXc "= iaCZ/ih6T; Q.E#u\LǾ}DZ-|w浽JQlGA;4'҅t;1SN4G*r1c}:OOt˓uq uGdnZV'o yG {&ğGBMf$(OzTM =1%G]v*w$&/FpHt=59Qj2E,!KD蒆9Ј >۵cM#%!~c\NƢR4&śSAtdcNJ^?ϧ 1OMRq!D($Y`q;EUU$#n;i1̽4clv7}!ɲZu xX4вzgD" `07{kQZb? 7I?#?s[ۗ]C.IeTiW7M;)3zŷݒ)|wcWιc3)#`ȏQjQ}Uos)9f2y|[jg ԓxۇ)g?~Ֆm{t#R=ch2'M&\k3 xP4Z}->  $ 75Rc6{-_3>mF龢9=чw;$PyPc.Xh+ ۼ\;T^ LIjR!9>M L6K ޿Mf"5n}}u2ϏV^p#8Ҕr8yގgoveCJ1|9җ#1+D oߵL61ÕJ?V?][ ` Oj *AO,lٖ?fSt3~XIxA[s1&"7rZ L#2Tٹ79o c]T,,&ٮNi &`f̸wD/Fc{nˈp+j5<{W\=XCqne5dZ )2 >*nv~8q}>aJ7 f[Y+g+c} k8ω$` C:JjyicxQ{+鶺T ݳ/6SRnBsQ!w.Ceյ:mJ|[:wX G7JHZWy\aOF09X~Үã1=u-Z]>wBՋk$SMl~ sWj$o !7rsHؗQswCӾm6kw h͎yO7Gtg;aZ=-'KYp!b^q))1M詯o~266|`m> $b;*rU6*c"C;upmܬ:H`T*6k+ꈴi|۹'TU2F&c=£l4-yF&&PŧW1ʡSdp,u%,{J >qV endstream endobj 236 0 obj << /Length1 2516 /Length2 17706 /Length3 0 /Length 19180 /Filter /FlateDecode >> stream xڌP NNpg!w  nCxs=9aV{P `e`feeG+Gztq9:BhI v67??++ᅥ.IS@ tEptvYY+֜;@27u(YM vssgad6wevtcxܬ@Wd=Ҙ (4-@<~l|3O󿎘ENAUI^Q;z|8L.77f/O9KGȂ_OAXʎh+9oGH/=  ;-s%G&8_SmW hrZ97S.9XH4 h r3k6#gv +`bce?:rۂoWHw3J9;Z^2v.n7+xعlmz5fG7 \?rsX~,EHxX,EbA p?xT p>?O8,Z?]u89dr1wG[F6v 37s15_Yq#2q;ځ %#ApJv;xǃ_`?z߯&`ZHnd tXͿ 0h{+]s,lO*p&w{זտa?!/ຜ!'=4Np1Nps _׿Vfn@ XV) Lh)jgj0`N7O_. <d<@vpPApss׫z͑VBmBĈ<3|W]>?o܊cJވtGtu=='u! ϔ5 3i8 쑧*tvES-ƾj:_ϭ\)N+ |,o΍IJf = '&eKOOibAĻH %xeoUݓ}q}D6 ɗg%8~6963N^^ѐKӲ1K?P%4bs uA Ik}evyV4ɫIm:S&eFfct[͘SP4VVTE\)R]qUѓ[+Chm78Ѳ\,kzMåEC)xDRS' 9nQcåX;ZE*R?_KXg)T6FM% j̫'|џ$HY5lx97ߧ=5Z8M-4Cպ׹(@G9ig`fɆe:pmBua?~3al^m˾}o_.gRte&җU׏[(O,}̷h\[uj@_Ҷ/҃o6.IZ2z8?i+=E3 o$ʎ3uqmtunݫɺKF&umEk+ y>qCf-,rp?E4ޭ6el<}$%WgVtY/U(@$&є0( JJ?ʓXK|jlR{B\ DKmxN@x;أts,Αog;Rݤfm4I3]9?BѳYyqsV4|59c#>jcq#K9Zuw)m^3ΧE%sDO6C@9È>&猪KE1){ǗeOVT=NEOK2RZʄŦ 4_^ˉ9f};@ Τ3l#s8Wp4H9̨ѠRU{Qw>%9xd&FhHHovk s$>Hs)v 2"~By>Bw,_NMK|H %yR(Y]agF3WjKU_7ZC]M۠`KǢNMÛx֙wDWOvUuZNS&?w[}1$@v  Q+ m<ƯLn4\ٕbzXZ Koem׏ W TU@ nPf)rVZc:PgTVʄ7@aY4W%;Ą#eEP=3bǎllÙ1]p;p7(s >E6Ҹ gт 43Yt=@V$&G@S _7J$&"L B ?\, /kOkl=J:+b6`ClstNA~y1@]ioqG&!;*տ|FJxKrL2WSjQC|pL~58BNcv#vNZIJ ]|X/|;81L6Ń>ȧQ/ +uʯ^4LbgIšOg&M8)D~ˡ2>,m4(CV!VKyJ0&#!Ky6}aܽ>_ =t,}pn{umr{哪*XZvO[2q$t<\p浓kG\#ҫs>*e)c&-؋A\Vȯ( Ҩ)}mI§WCдAD8+fMfi_n2Su 3[v&jEjo4EJq_/b6@1[%@="3ai41xް%#2+;8>cz ,}'~5qiؕp-(oERIbn_&uRCo`(W"v[,ŧIi!48su!LhZ_hkƕU[&jRXR2~S'9A6`W <A㥞e7Ű MO!dlѦ$8 m)H[pf}B 8Tc.tW;t߸'ijbeN驏gFlz\nJ+PXe:dϯôN9hTQ]3e^236. :eQ#7tp Ep1;0ޒlPuݥYFk} SaMkGSh0SPnDQĘ!DWW,jbT4c8„caL T6c ؟{a&t7sx=iXru^?rleS,iv.scg2J{~ 㽯6:b\5J27tvk o)V&.2 HSu 2}notTtA XCI zAzztp-ˑT1ؕ]%0~=8f!Y&Ƃ54sߛ1k$`@z*r'ռzMąnshǞ}nd BDw{|6[\.՜ƻ<:Nuw}U7'QG_dsOCpmv̰&x3YLxZ}${ߜ[]kȫܥ)xCKqbaV !`8blʇhWn<U3=Frip)K8DNT&o_sȳ])g c,BdbS)-/gSw־ĬhxnI8QaĦ{^4YbG@61GsB"N#Ҧhh}=~zdzc<*%1IWTJpG;6|r\q֋L)IpThxqǞGjH- cD玿!6W\c,Ĩ)(z# Sa7~bI>ۺ+IJGt8Tf=*"C#R\%"{~urqP:P4ч ?]c }<l8cձ84sHN؟zy |PYP>xb2'YӒTA {k+Iy#Ø:d/s\?.Bg:=g[W|S: ^{B[`IQE*N)P(`d-󖠽LG+py )QٙA-pF#+昸f[*𰵈 QÎүtwĜZdsAP`%gI$.SM\R~)<đ"Ȯ= Qu7_(\\s5$x:[75",cx&lRѻSv:Aҗᒍ]V|̛dm$zc9*A'G Kp{\iwLv[ RTzPadg&h'2 }ٔǏK0s-Ervuު?W-bI0;}< YCK?A=KB[ӭuACCJiO=ȓBWlu|49!Bހ4~C\c>'  gHPp'*tWpa$qk& u=%6EuzkIh|<.梳FmF:Nj.Yk_A6NJUR4ORjĥg 8Y2lϠx!=ÿ<~oh-TY- ύ=AOޯlO'"w2>tSigc?ݲa.i{,4A،ץc+ ^:npIR|Zma|4\_6Ev!VEI?*ϾpD[荂C"MdJ-v?xHƢJQgwqˊɲ-pam$gI#ŀS:#+X%UQ\q!inN[,S1w׆6/ ey$J.'˸qg7Dͭ}ôcv]cHP4-R`gʇby*}U-{OnK/#,٤G_ }w4A#|w&Sg\Odp /M;DT3Q8 x+(~mN>N/.Y M跿gmGYbC+, tE k+] bA N WFg7QW۽{q.TβOفB0iQD/BdO^MFlڲaTn8b=|V7{op< ^.B2^GXEb4!.:Asķۑ5)\jD*?0Vď\ |T>@0t$\W /RXNp0 W\=ҶYMUjFL]1:N[,_MK`UjߖPtRiɓ~o6*vZ˃L08]l>duA]J3 Q*MI׭O>2pi䐝3VY-(N{9cԤ{ՌU96Vu<5o|t"ljV $Z֌AU_u4=H6I@54Ի/*:W|?ixcC}XK ]նE0 3ѤBtF(]r!l5Rw7Qj[Ī%$1|/-Ve"lؘ!1wZpM0(g ߡD?v=c,tŐNsY zpYHfkI ZƫH\']̨_̖gG)D .xeN`z UE%7rnGh *3nv;OJpc6D2o=f }GAfzw@K5s$BXQzHRS.Q8QvQ_NRC_Xdb!H8{6ЅU;wgh ր6 #ˡ?̱ux\=n2 O~$]+aBlv29J1=0Mζ:ڴƥT^},HGR1-(1?ˮX޼\-} 5S_>Zc4EEԭƄCc!G@RYBŝWh܋3+z&wsݗq=z .~KBAqLw[{DDs^{bfBO9y?X>&36_QxpӦFΥaeQ-|g߿nujHS/YM i@[TeZ*|C7+lJ&lrce)i]-xK&:/p# u5=ڲ)Wm*l ']Gh57SI6v[1΀J;&Zvutr#EBisAXo"H'mog,r<9'tԈ:vS+Ѧ۵-8\:7It="e^KXynI F= )F7׉CU>o{~B!+wg11{0 ]X<{v!xyUt3kOdĻdT Gw%<(yY=p<} +`9Vw]վVAU6GqG-YP 2E,yXҸ3J1v] /_;Jn=;!B80eow&a r%>KEEO+wMHrE<,сLߏ,ڵ=&_˄f&zIŠa6摤|bD<'^ lŜ0hAXx0r1ULR?RqhUaq{J vQoJ\Fhc[/عMԏ- "UȁrxgAC<&t G*v4TZ4a5)_,4P_,ݧ.E|`qQ-a4e./\~՞M4ۑB&& |Tˊ['+%fgZi0SP66^X.`)ޖɴkB :"n-$h1֝&{$`=#гB똁f=:BJ߾ΧB$y|4Vey"|MjESV|,{ 35">gkT9LyPXՁ[q߱N[CNn]kN!J̆mA~'D>.s7g ]uCYrgq*yj?woMÜ#շmr: " Mxo| ѽ䏙ܴ+JSʧy57I{_BneH#uN X>4Jƽ ڭX< ~8+%h^rjg6;IGear#a ama1nliE@-)98IC~ئsݯ1DX=:R-6rys:8qv;#Z0+6 īn 11hcC ng[XD~Za}u[S)Ӷ1-YC3OK0RBe9BWx|@zWp4&O)Emr$WRkE_Y}}zl6g\TI} Y{hںfX4j*#O+41h{d79ZX%M[ |^)чJ=:efiOLnMtbeUO AΒ7 M}s"k%,bԴ!rHu#JZp ? rѤv%QRj{IAD =!=u /ݭKn7ΰ >WxqbIEװN=* RU%]V9+.]Lݓg}7@ՌD[.:8$] Fs;[Y &U<:R|V߲c&وr'ʄ?v5-gL3zDzy TR=oi\RyLX ;tnZymrrtlzÛu,2X}v-T ymrS\leʳQ*0$G?Y 1Hu>xi[Vi*40m85V+ZKGB(-׫#]$+TN1jSȒ5#&s]maex'ن,CΏ5n3DO A7؞tc2X&|tWY() j Fq&]|J.bLM;8,%W-3Ҋd:PVO?έtlsX"SӻB\3@Q{}ٝg{3BK9F}2=y|'΀ԵZ,XM0Q߻ <<=ԣ.Y˖ *uE:!">]}XeyDq]*4A&lh\q;VΚ#7t1Z,j_ޡ.鞓홟c5R%ŢցTz9z^ƶC)C6F-rozȔoײ ;v4S|ս ϿB0d<_B<\uD$|7{&mo>jj7sWM)0. qRk3]]+-G%nFB0>iVQUm/O:믨 fZ:2MI6h.i~b pMй?zcNJ7ԋ4/A \W+z)HӨ?.3_6MtW|wPvf2Z63k2xg_.d#>G 'ѿMat|YI֨coC"ف DM9߷?ɄK+1dqH:^d# %O nDg9M킗dBW|ϐVf_A0$,EҚΆ1lԩ[\BxyT%Y½@31ᵲ/ -"fHmlξ磼hf$$GZR>SR}InLW\KD[Ame3j>5/dg_. CIsAdƷ#=>420@wAqF(:ƐB'O])ן6* H?en?>rlB1%w쪖Tz)}3J &ʑ؛A"3LvTݒL%yNQ*+0^\<nٗ"%ۯ :GW G!g1?G>ˋ $gJà?R|;BU!I~K.JAcm1%ґKQ} i&Dw*qkkuEA`Y|JѴ@'l!c Rs6rv.^#a~r70;g.pbHXm:Q+mׅ Nˑ%rũ} 2'_ڥbx(|Iox= vvqþX-{.Ks:}r%vϊ,vv>cḥzv`a$2. }7 :xG(ƽ F~nAI z y>᭸> m_Z$+A`8M'/A]hup\wK˵+)7jߠ)ZY]8,־ӈR8yݘn>u[=BBWE9K܄3M[yC3-9ڶ|W|z1]ʁ1?5B$#|٢^p!5a +5S QYGg얤GU&Jq]\07CR`W?G.Y}^7/)csr{rn<\aJzVI+i袠U GCyU쑍Kl-RO~}gfR C0&2Z$-F-} TX1:(ޒL?] y .H ,Uy6z);qݙ&` ߶hae9G5 /rҴ[Sg$q725f:C b~͏:1}X؜|$Ygk,8 >IZc^QE?VEdjMٹgVVύi3 E.i+B[kD{e!Ŋ:嚘TtI ÎMnԱc_BKru$-kTkcl npfzd$,+?vhMM{'VSE(rzȹ]PV!+ _ E}?G zVT#^CLGqBUZKudj.e_o˹B]2LH+~0[=1=zMM;<PX.DQ:%roYT xzoϻSѹ|JYoZn|&s{)6絵`3G7wޠK 0Ҟ%c _< B&-^J7' &$̜?-];zo ]3ePę6=p1D@#+VJ*6bQ~fq`_l YAԸbvV5]2s)R12|~-tŴq`|X)MX`w,r)(ʎ;&jj^k<9,#"Gz!H/faM%k> ΄w!@ ȳ1|mLFԭ7 i+͓O|]DS=\i_Z"PϛrKO V5jžw+V lY\C؍6}Ig]{cϖh: oP݌VFj*s\4FL/{v φjQNNh\p@s&FQo#+"Jj'2T"6dNr03Z3tTNy1W #e5XU2'jF|q{v!Q46kNocqAuNrvp}L_kIȻ.3<K/R$nu"lQOHS{# -] TEoː>ViaM '#cMN(9iTITR`[My)&f.mGZCNdb1})VWtmlMJں!B5̠U[$z}ڢ,)?ue1UYl=~?IHBt Cj5b"OnY$5_~z\<Ty+^fm$e%Wdi6$:"Y?dos5\Z/ܠv\ }I1@.qYi&\noN]$==Jz&VPvjAOEjAs,YlOi_Αe,0Xr\-?es}'dZe/,: 99ˌXm H*s2eどdS,}k.sǻ%_ ]w1$;(c,BɪKTg/Qj3kds 6*aK=*g?8hYM#hɛ3dJG~\&;Uq j`V ɻ޼݊kP}[?xíK`DGz>9JOX2b0\:iihXD:͸V673j7\x/:ӈΊzxD)X󚭦FzR.Xv5ؖhbbF<&ȏ6Ⱥ^n}ɻ0j+8up* g0a|2 ׇSGZN#4-O&;)CܜɁ7Q"8wZ7&83K_NaCy _3LLM[6IW0's[`Maiuwpq>#]'( aLvzXmV2HLF p E.{ ɯelI"G;cu_m R'?ᕆ-rGrˌkDs*N$Ԭ.s롯Oi>CH~g?ÍQDnI؂q"H,& oG1x{CU!!):͠w8Nl"ʆ,1mUWaF.;;h#2᭹Nj!}: MT6[85n2\F^XiSF{SNRmNa0:]UޣH~pliucw1=3Fζ%ؤmzKZI ]:.`^Ңwo)){&ж$.hNم_B{c!\0g0aBeTWN :Rvrp&H`(ncM{o?ܐ7.VKDޭ) ,fJv2G|  v)-%?*B9CĮ4R..u`C ICfcl{(X LWwOCщϦTD9c0P^0Fp%nRD Dݣ|iQnt$!=0G 80ˣOV2|+n煎9g 1"3p z.0O p,:/&|gBY[%tD^+Jl p=kб^6̝]$XDRJ5SBy zNNXu26 1޿P4#H9iswg( 9>WC7S5EPjD>JrN6] A6%uMȝtYt6k\%Α>~$6\O_Pqj|l%k2h*\UAdh?-q䒢iΕa̾'-`iDίAB7on6&i ^E!Mn(XGUWۥ~A~؟ƕy,*խ2ig \ywu+hG&-op)eA=A <$ڠȜ, "k|$ ^{ UX.݇zuĊrW%.Ex,QIQgNo[`,?"W}<Б  JSkč֖GoG1F{W{;ZWpHf5xnTd yoK5dg_\uCe_f1 `ߨ֘į29V eeVoma( h > stream xڍwTT{6%- 000t7"ҡ t7 *H#Hw}k}:ks޿>k]y!yx%ZZb~~!^~~A\C Kb FA0PD; 4ܡ!$??@_?@8BZ 8 ˢwF@_ 1yg0b H݉@(n #]t:2Ov#< @gxqY?zP-v0XWoW 3yC`; QEz!@u=(;s @E^+lD_a )0 ]۽L %A` _E]`Ww_;?:{0 /$/ ^|z~*uCw\_7D}El?`?/9,àϗOQW^WŐO^_A @@X /w] 4Ubk2-߱w!M]o ENH mfm?@g@ F7gU [Ց;7t!H[?߾0[8׆n>wWn@`;;`G)_g Sl==ƻ#^J0 l;5 sk:/Y~e$w ~y+UT>eik߭*ȆDƟ~WV/Vq'GɻGr+hqhx V]Q[5X޸}Kz٩UU831Z*3 ,96)1<؜$^_ONdk~!`Ÿ\[3%- z7߂ݓ^unMSwSCR=lGbb֪GCQ dCnE;, Ws͋c]R-NA gľ 6fx=5߶ׅGnp^ 57qR^>b_dY<2)U 8yk콺'|>oy@SĠ=LB* @dz; uyo2$(r]II_\yg'[9 KQqf% cߣ5izkrQeaam:Z|k=JޙLUԬ!DfhPjFS2ag0yQ^G>4-H}ښֱ# |9"#7^펳O+ F =ꁨoV":.^dd;|s;*Cr|Y Ϋj`ޤw O.ԪJZOxu0|ﻗd1-U4&1txG \=[G_uxi ߳WETs>x/K;7p8 P_%aY_oj| H%{"~%]t.V*Lecw22f '{Jcsk !E3 ߇YTf*M>ɉQcoZ5}hզNCΫ|Ŝ roƽV[bOifӽ:hauݻ\\imy[C' &rpwk0~eAon*OfK}2+0LxI#8+rPڟ mc`^F޻9j8>y-Z3aDa(:C)Sb34=h c߂pFg^%홨e,$ ̙qL1 ~Srw?&e< aJ$멏L܄;DاG+[ҾIǘͽ79syS!9BVV}HE.r_EE|7F|! })1<&(nA0](2MMj:Ll#ij.IO?V,H5n3lg<{y!om. aa +CFi~&t8pQ)h۵|,1M]]PíI޿IjVq?Fxǖ',ɔt^ݢU,|ʼvt攍yICբe+^;K(۩KΦDNדSnh-Nj: hd["fkFϾ涱jC~I8l }y9\f7?q37W?zVim{d!flPZkL/ͷPes_,Əy,*(oozKL^nd?ph!B84WMsqd#Y*'A?i|?AͲ ڨQ|Ka%{Jã}<-gMzK2m?iqQĿ}rN/LjQķXSGj/]j^x%}AGJfE%a*#.1GLhd7k!&_y~uk9)ZۙWװԇKx؇γyB]=f+3 5q#Ih_nt ^Lpw̾:hW\0%N1 2Qf0,v\ O'8'/FZ6+Uŕ3 :$̮ra1Ir EEuȚrR'qg5z9.JeC^O?5V!ÖS+灷PGͧ9urdsb}]4wZ0o{INlՉ.]VcO^"|#Y 6^|Ѐ39݀:O8(k(}LJGlµFH5:hen~m lD]ucjP ;Ȃ]=X Ba刨U# XY9a?O:lq1+lʪF~O|i@]eq+N;݇xc"Eb DrfT1qr)wDClAHĭz9ƙ77quAcgV_~!ikyܡ|BS\?vO^ ~$ӹi  ^ΕMuWH%΃ CeG|[zBODd6߬WpaIG:gхE+(S5&kf$ Ikbyn-(.LD79IM-i/ 9;  )E(imMcXеøTꒉ&w9zC} ub/n2_>+Z©Ȟ֫T"U=AM ZKla!TSO&!C.e/qi1]]e^PgdjF~16v 8]&ڥv;1SeU+򀫝X\_9L VFayصx,֦W-ͻ0'5d!/FTȭp2d+\o0h`%db>RW<%~Fg)h:Ì>)z{(86^JsLQq,%Svz[}~=\Ū"Z|9uگbPkϗ X11NcjRD\⓺uFS +-ݬ8޳E/WI>Qʈ0T<xr;O,'zFfwQ|Dv-'qvUp.QU(9]e LUDAfElνeS/%wIyvɈԄbʽAw {tG.^'9<ɩ/V&URRk)lRh>./b8B۲ {y!Oao~Zmn\bR`.l\⦆n'r+zGB H/4Æ v>wёs.x|=3Ytuf0i/[-4ģL Au/<Ԟa0Q@gfAua|]3ζN8SΫ Aåay(D$ |&T"ʤ;y1+{)gǨ2rdWU pF޸+{k;@,M2NЊR'kyBʄnK4 *yn-SqSx=z{e7ȣ54 SR;<w$kx]4s=N}oqVʛ^LHF>_`fxI\A~"s=fez2\ ӛKP,,V9;_(-mg1z< pvQ~hk[;hu؂aĸdW,N#+n򄾤.E*; 57ӏ_!u>fZYd#ؚl{q;#m$T]3`&SbGiʔȕMLm34iٞaAfit3B2*[@7|NQIdž5lc CcQwOh4iUkO0qSM0g[MoVi,D*3_BbKa?gj_ZXnbՎaM$$={4iQ{H9Lk<B@/eJUozE PůVF-㗋FPlj?XG}F-e{ -@m7`E!{%Vq-_ +圗SRm[M-jk JBWG80ccUK Cmn GkDXdmQd==)7ȁ᳠@כEDIRS3Dtg V*b))ags`Fm7nLCo!=qYSAX Pr2AN`| S+t5vnD-8Mٿ]F|q,1s4U!q]wdO"Z :ܦ:*8Uȶd d>` QQƃ85RdH֧2?"16ךD19P;^ʣr&2Y Xt@B\aM b _>Uf@h ~UThѳK2"OX_RUs:ӡ3e۷\{Q)KlVPYc:,?>~BADOS\3-[蛮/#sھ!~;e%dg$" B?2H=殙0)@yrJFG{| YKTT8@AsBSf8 7VGNƍK{mo\!ǭI3n o/9*ۻoGUj-c yԫi U! M'¿9,^~1ieMF8cvSkbK[.ɩl'| ,n*D1A x=uF:ڷ5 TGyEؓҙo/+QH~.T3wƖ'qMo-vԲUr&tJ߬(e3'st.|H,=iJ`ywA dwmc`bd3KxDLR:8-W+/ )˲PĆ5=e٭;qG`ȂW͠W3c?OC}2u˨I!QdqJ}-' OmXKQ endstream endobj 240 0 obj << /Length1 1608 /Length2 9420 /Length3 0 /Length 10246 /Filter /FlateDecode >> stream xڭteX6HIw!CHP  -ݍJwHs>ίsϽe8<Ş]V.'8੪?xm-jBGL۟ƞ`p {Բ@W'S'0'_n?p\6. ( t'uo{oq]Pkn >V6ϟEQY;x9gw@v퉄<> [_5ozZ մpxZ<00@TOc!Ba.,7<yՍtT85:\/Ke ְ@<&OMm?Zr] ZrsqyRmj?K{0ă259c &=]|H!NzyUi?DC&Z<:ݯo u@Y:ST lym/86ẙ fWy 6~1+Chpy~t@xgZG܎׀@Pǜ}y7<8yҽNɑ$nAꗼK4w9U%2Ng3}]͈ň!K)Cm{:MR`5Ӣ߬Ŏ*uk;9kʑOޖX˸Lnpm`BU꓈٭L"Ÿ`<2e' 0laR迪R$k6=rx>r|m8%ɅenBsjKzW ^Ɔ|_$›+zKtgP&:_ejсff~?` ;߀P]%zjp,Z͉g5_&G=zL}l'j:a$e:b ˟ѝ?Sxc||8 &Bp,ӂgb֡$҉# ̓0<L2C10zW5ލv[ qk`näzu,/J۟33Kibm-[xΙ(XpO{I+g"}{*A2fro7Q]_*,I\8Y"]:(VuGcՅƦ4D.~8Y8Cn >@y0_'K}5LAnwEGQS1h*t!y'6PLFç.^3T5+튃%AX$*O!g\wsmk}jZhIsB:EQOqKU̻kH7hzHHyb7)I"wx 9C=ςd2,Vf~X6Y.wlFbĠ,#% Lej"SGx?/ u'IR }-5Ys:R5d+z^_t %՜_Yا8fp1u'lم;ب<'ܗtKiQTzMJ!SXl2\qSWOTc{ł[.\x1Ka ì]_v)l|N;1/|:SzGCT G3ڢH}GWzʶ6ې&u>v rjd|Ñ!o]Yz?H(&09fm`x$Z>9mB:h 'ǹCw\U'HF% E(WCs}ez8no"8(3FNp;[XM=|F2T\idъxءY n!Y=y-TǴ\覱W6+%G9աhu-Ep~rU]qVIkƋߴ gkg @Hg)I9%c JHGN`L0C5D'w гʷYˋ2ia Ti;n4cj-jl:jTt0W֕_^9;!V6PR50r{1&ׅ{h<.PAAuo-JE2*a1cgo)]`'\}A]ϘvGoDrad~,[O &oێ|‡|~Yd LQUA.ҽEԡ-lx-^;M 6L]D1;[ɽyl(IRuAݨoyE$ѷ~̙b$|6}icBejnV[2_|^m h6~Ax-TAIn1Ia׼Z龬BO~ѥl,jљՇlLl؉MN{ q xo̕1,xpb.vh'lgZmkR2g`BXX>ϢٔJz='<Adjo=n8ʲ ict,aetc.6`'*uJW#"S#BdAQ/[A#w_gV*}Ac6CTdSDИJsOt~؆8a$2~-Ցs\wi9`Q^ŏ?"]a'JzS6w2] )"gQi8p!)ǣpE:;)b9\?.lN!V WeH-c;M,e>Ð "'rwUO0g,#.|#hav&WN' k ZL}|PLH0/K0:1[t)OK_kL Ҥdbi| 7_r_7S;h5.nEm Q;^T湸Y6hAwDfZkă7A EJk Ջ9ᅑV f$[g#`RP$~Jx|J1L~qeLh{+`Q-CDꎮ"2Ldc,gM5<{#S~Nxh]Sbp)*'ns|zpO3k xgըx_iv&;Rw9F-3aQ[$nD?g8sڕ&!Qֈ)0K7$o,g!sVNETI]p { ޞw~"ŧ$5苫&zsȊ]2F (*!mDDC@%cXŘ:8Kb_1!Jm{$[p6<%?`>\8jVMvNDHbhPu s**{4HD5" eGFdžn |[ƴO78aŲ4%EBHx #}>DΡ2ǽyDM)z;-ep-tTӭe a>џU2O3ǜ2jYE@0Yr)'~γnd)?R VOW>>5ǥ'fr" ]/3>݇cR5 }}idĮv$J1to(7 h&[Uiuq#(Hy[=xVd+*p;#韍l\ e< n3:5ތ^ ?xtQn34B=qCLw yn6zSD0$Ĕ0ޙ'kY]59!-k<ʶ_Z5wĈhHghY%=GVm)59| gˮ'e-MNՙpHhٝ>JRr\Ì=FFD ӧ7b/NMm*C&'[cTJ3nzp6cVzlu٪P1 3?t}^Xq.1>4tWPw꺷._٦ׅd)/j-?}y)55@}f$r mCFݣ9'׼gc30'0ѭ.MٶU/.'|&,yKrlgA΂CLJpx_S?Bge#dq&N*#j! @ ;)| ei`wG`CY-7Z>W'@r gBS5lw"F @ƥ?$). E%/w/_t9~ISovSį   p6l$qJ4$u0^\[S h;kbB7) NR) MF~3_@]C$+oCKYJy*Í}t<=bWyzyQ\ogK{OnC+^t8C-=WWz c}"v=tP00iȟkc:7;:uTW;˺^:zd^$ (H"=Siea]ۘV>7@`xރY'DPzZe#Y1S[ BmG&Fۛw6Z%#*{KLZO*b8:Œ6>;6bLmh$ OˈLO5ʱ+pXdxіW'KyVX1p&YHP1.8"xęJkM*|?Rgntl:潺Qe {uuNl\].ytSyӪU0J ;(!"uv;"͎;GW^1cR E~R MLxUK,f[=\[@UADw-װp87I= qb;•-KQ͇c=e~b"KfmI}dxMm)}s1Oq}XP+21$2(d_[k U1Βȟ| r}rŢ1lEՂk!YmeJ7dZQEUF{_3PFteCKv43C.K@?ky+:w IeGhA.wP Pz?U °`ɹTe׉I'?SeAoQ(K=/=ls:c.8H:TƐHQyۓמF.G.4dq23BI縕 ¹$5?ڀ|8()ԥjpQda4b +Rpʛ"8⵾~D.mٱFtd|hbL2ܔOQ- S$GjPgb{9P.WP?>L( 'к% yz\y# cce$p>tK2!8ГVr@|+jP%7{'A ?VSvZKTPhbnpYqܶד%u[\-fy-ieJ~Ip[뚰TB2bAWfȧ &}쪱7H*FhuW-÷gk; 9o[=?<VY61 2?BWp{Jk+=CK 5x3AfUjYt~9Y{'+rOgXw/{puRoWizi%tT"09Q5h wPe+Ӳ[@XptgV;~Dž/8\Qw-X;=o W|4dw,2"u4 o˂~D~K~"0yR.KSR78INN2 ܼ*'qMp8Pv!!_QmnZӤ/XF&rS[8ʇEQQcTVJYof*08"Fr7n6!'2\O3*tc\u2;859 $5%(Js^0d\ Ϫo{mvke37KŬbe2'Y9z_G?< w]dM 픇&k#NۦWI,g Ď@c04/17Jj7%=켉5IʼubH1rkKj@̶֗Ra9?(anoD-Xg!/w>%]!pڒ~im5{OU곅KXp<:7-j23H2ѥ.huhL75L-T[6}cW$Uʜ׎K?mYQΝb2 t-}k3h!ghK}yECE5;S#ЇKt wZ՚x-ozNcd?_FSG|m卾b]sf],vc *aU_QI!Hbw /kI6[ .9([WWgc{J*uӅ9kbip7_ ^$YdEկI'"kP֮SWj? geD_OH"  ֬-_+bI4 T_ž3Ȋn=J//{_s2aM#']j^Vs T4| egQFv ~y^%UX"m-BAW%ҵ#>~Kf` O" ۰aR'IM: -dEN79rkV>7oCy2SioNO*"uQa>LkEҺ bB$m'Wj♼"leknvuڬ-Ɗ|KuY~Z` `% vE2> stream xuS{}⥣u|uɤc `4GK>tVIW=>'_)gN/>G;[nx̶)ނYwD'm̞]j6o P!R Cۈz3O>lqخ1)]yCJ#؂AwRŽ5jidGVRw1lRzGoɥJ %,+gv2s&"u~Ѱ}t`av{A?\`T5nHw5z%Z* #ʸVktb@B]g\>`rp,E:a\_YHS,}V$h睇쬳!}d!s  ֤Usɧ54 o: $WljSN}Ohi]:^E{/.7җO 4m{B=beOf>h!~#SDDMT g>RewkjCyJuLh[A']̙:]-jKЯ0؟wԖw=֘rpAFʽyb{/]k3qOKW{m[02;7#R}*u:)GJ$Iޜ?b&>JN]0n&_%?SӨ3[6numQLPgq^|ў~IQ93N[uw=3q h ud $Ece䞔&T{ЈSVXҸ챡Mƣ΅ۘ5ۿeI1AJ:{my^%'D9!𧇂|wߥ$L )ZfJgmXQ#5ԍw[/Ҭ|-**|+>ٌΡNءZ"g+)KθdS)uD$-}x\ex^dӱL# '\rmgT?!?=n-&ٞ)g%W0. xC-곏f6u~\\~1v__S砮K=t%q8%έ| Ap1->6٧ԥ?݉֬E꟫-m?8|}ב L]lKU%78)yL~6Vs0m ؕʮ]J2>"t}`EoQR\*m4i娵<Sf/wuskedk?C+8ў=: 1푴feoibElBm_}M UzXq)MSh&p4Sz)CG:`1GU4o0_ޠ endstream endobj 244 0 obj << /Length1 1626 /Length2 10416 /Length3 0 /Length 11257 /Filter /FlateDecode >> stream xڭweTܒ- 5nFwn .!wwwwMpwgκoޟyGէd׮uNR`B@{(;0@lgS))`N d CM a\BBBht) `Rabaaz^3/ [ NP+l H+唵r {-@lPAL 95gW,Ig)d~Mr@Nv`g3:(7uEn5 q:;תҲ 2U@,^#sZ ꅚP;Zf `kZ 7 g?@N@[++_gֽِ `G~i}m GkW- .؁.s9= ƿv镄)bo,8!ג> ['j.}WhY[[eSx}dL @Cbځm=_I[䡦#|F,TCͭۮe9قA=R'46 _<PMWnъ_`޿ظl<\w?Po LN`wkߜ\w Fkm4M/_ns'W]AhKs`Thav~w'|CQf~/PSe{ݸsܱß]N[$y SW.}^ QfNY O{[jFOH-Oh6 IZ$>iH7|Lp:i=[bpp<6uo=IڲmEe!}7,l",;QF;SaYr/hiRg v L7,9b _ī`E3#E,O%JZ89^Bqo*"ÛO-##\Lwj\ EbZ] h-.veGcoUH̭,PD$T[`Q mW `.24.۾cT|iqSu|wF\内f)t~߻H+gAasn6 fz#y7L0ղ Y77!o݄Y=!qL&IgN7QF>'j\P;% 0^A/D^y{VlD[]R.7$LcieUs8r^URq83a7'ZBcQ^/ayq:3#=:JiEB?OVem1}T^ Cz5obLuogt9(]o37E^^ ƹ9<gi '%4| $*fM7pEE".svX^ $eVS $Yg7qS0crw\1\sщ$X!#L'ꅯs) {-dK1z?Azq ܱFpS[$ F4^k68x5G{.Q:IlƵy!b?T*Ƣ4>i3k4>AOIFA&[!<а+YHX hGJ|HM' `;MԈUNFLjY3-礉Î SIcUqZOV x[2iR:Qphin}I4^L#;F֔ e Hsᘇ8Nܲqz\-̟Z?lXx!]8/Os 7VdHd읆V3YǠq>|*8I@'-'x &6<1xмO\2 qd7urÇ2=wnKN"|&rmu # |YQc$f^c"eg~MGh*/ŜH ª0C~Jrx%qľ4:ۨU}T=@nmۼݱ0xN.zgopO#.AĊ4XWe]rB!Y=ŵ'?3@Ufc V"3\ANh}OeR|iN@o-F R_}3lQTDvY(]L|to pN`LcCz~/m-J- kDSa[%ғ8f 4r3l48NaWLVct}DTQF W^cklG ju \~BW̟ݲoܝŵWd,Y)c :W>$3ݓ?1E.џԐt% :}l֖C%(0&F,{n9#`Zp2xGagEܓڲm+i1+DrVggg5.7;e4}#b$5w%L2Hp#3dF 5I PԾ=9x Jx٥Ӎ {R=C<+:#xӆ# H2![Fw>nM }jʹ$1mb`aWzΫb獊ؑ5\zݏ)33$m -ƠuPƘgl ɳ eb"y~,z*灕jv0y1Mj7 ??D?˫F48fҥj2;F:\Riˈ(і׾S28eu琺P=w0IrjdD46o{$"o+w2Ǵ8ؼajFܸ/e6؎2Lu'em/+ky 䫢ہ4`+=jk׉{GV(\iu1L ^BNs^mQД0z!ox=vxirSyo<)$c\OQru<3O1E逰Dv" I:@ ^bHYW6w{5 !/8b/HuDrY׏v=_t۴Aɰf$MoܲiʹCrז/D;:*۞ tgJfm+rb Q߃l Jˬz8٭Nꪮ72%d3 [7|i$EмN*6jy-Hɜ.IZ!vA<<˲ڞ(xkC&|?Q‹OA)"Vх{;iWj.h¿ǚ<+˳W25r6F|%U\vR6 f?aF垱v#Y:0~(}4[cC iK)NHEh悲,|OlKljUAI&['dt 00,3u)H|ݭS~R샑//'b\dl h>_I!cbpKmPKEB[aBᄴ"*eg`Y@Y4fwUD?Nޞr;t }aέZܣ8''H.~;2w׫QԢҸ{`$J/W>ճ?LyQ:ywArofb!|0òį;AY[t'pM0lQ=] h&㾠.7U z[k},(&gE {SSrVghgyvaer.) 603Ӆ:\L:a;ěV YWҟ+k  1w;XTD) `My~rU(ܭ_ 5h˼jqaC0ӱDMGiAɨ 'uY\tdC\I](eY%X9 U/yX`EP+}{&j  ѲN;QeZ%7Cn~i*(!ޯyS/ՀLDUfU˜*׏FQ{¾h(>ֽC\69jk|XE.A-F·g%}|! x?W;qމ-O[ h *],Fڡħ3wgVex$8.(LIآ+Ɠ~I6B[F ȥQWFXVB(W#r$o/? )tzehdi)3ߩ+VHZ?l 8VgIZk zգXI`2Ro}4>P}9/z!1olv>:C@!X`T!9ʋOŶw0 w۷5oMJlև> ҡYy]j;S4^ZT3ʖu0dj4UIS ~J) s>b81 2ǧ[~^3~cpYt7G' \9 bUWk?⹳9m{SD%ެDGenexl%(yIޟ%a)>E'[6vN5}5|#Z;X-bXO߱M҉ITc> )>MτBdiAΈXa}귏\-9bFlq.bx{N ~V#蜌K:%}KCp WSc7K㻌FQx=շ~Ï,0uQcO}sjIU@;^}U1=XdɅ)D ,w?,P_s ֐,=+살J̀vbMaoqk6nB簅~˼olTh̒Ji_K$se-YR_w F94ʵ >8?&@i[C\H@ڰ y&yelX%ב;YxUZOv``s4sy_#~1Ϛjy]cN8ӄwV^o6{֨4,8yD(߬ Wʛ(t? ߬"m,+y05G 719&ŀ)z{iI)Meة-#@-#TK)cJ6ףgf0l{s; }"I.1A\^x,XDl~!ꢡUxCڮ:GȽ2+Fzy] ϛpR&~sI;s燔j'V,ȵLaf`t=צ%i\&|BTLgQeⴑ=LNN!O|MsY4 -I(Xz~VC&?ywژ!wYR3r%ARMf9jJՑƦZ*82mje@Hr/?kU{r;<`? چ >v˭xjoa:XJw.IrKH;P^!s-DiјjlดOI4ImQǒ Q~7ڝwl]lor|KFl#E:5SRy:@a%S(tlK: 1&].# ]H7\Z/ߺ+: ~*W탭BURtۻG[۟4KD2_,?.IĚLaP4&5r}Ӷ8/ߔk=PMms 7eFT A]ܧ(pSM1a3>٥7' 0 !ǚ7BtvIso&l8zJy41CH`Q)x:ʱou4k=O?țt걺uࠕ ;Z^w7 jF@L >44S*Ց%~#g @RI "%Ob1?"JokY56xpKp2ϺX5`\I~"(Ā49v'wMsI'5 Se۶]{أ@jv" e–tZPkL9k犂 e$Kˠ5垱1+2$(7JֹoOGvq0*YqBT6@čnF8ϋ#)ZkVSq%7ٿyl0x\AϹt\J:H [ĥtkJt[Ӊ*rs!ϴŴƳM^WF=LRv3Q *ϝTr _wԴ%k*:.w7+1<0.FA=WM-SLe寿59'Nc 'dy=}fG&p17B{sa,~s\wh8~š#Y2U-{}g!ԉfx  Iz¬<*AB'cC5!}& H7C߸])9jdtTyNYY@8^7c} HR^$\^ DX9ۧ)jk2+L|&wWl x:e9 Mo<7NVfy$,Hgg/{%g1s<,1MF(HS@_A1<?PHNMzGZܛM94`/˹ܴ'Ti$ʹ@~cY:q7Iɧ.*Uxok."/)NEsĐR|]OhN7Iiþ*.a 0l )l1~?n IZ7Kr'JQ:3 <]Yjp?yMa\LAcI7^:{&SF}2Vp, HӬ[N&6`.m|J\+  ȩnbg a2 O#L+!&Li~ -wߤ[ A!A32Sƞ6cOz “K~.-k 7q~0{a8M+irV&W /)dnYXJk\Lj1VEolD`CfA E80&Kg؁]Dcy񯻏\ /~oa92T<{ 4A:,դ/W}%F,b{-9CGrnzw1ul2>tL_%q$Hqݳlς'Wׁ,GV“Y)0.7ʺKzY%ev~fѓ[YqATC-O pq9~ia 8sw6h#e#;$vk#[/6Bnk}C|7¨lZd ć|C总b LqQETSJك"JӀ@ihguj02@Gŷ͊7ulmSy<ي7ٽZ"_lʣ>ULimZS>HqVS>ETx[PRi9R q7(T r.jb[ND d9:@]=v~'27+- $RZb.l#t;FK,t^ϿuY.o%p s,Fs3 μ*' ԶFpQ~fta) ,!\xdBf߶T8*Ē r#y(^>NftT

    ?^W}b k\zјw)AmNI45XΚHÜ6!ƆY8NvO s'$ZLd>4bG͉">#a枂`ŵDOϛ˭;QٓR|N)_AX'8Gz-"mQft/h\kY>Y.\#tx^TLlUĤ"MmʷaW2FidƬNS啐A'6u_Ud+kQo~Zu)Q%7)WgAtEJ0%iA9؂kKV#3,L @vƧ%PVzT8ik*I7P:Ś!+'{!cfi a?<f1liMF˹OES`KDvuQX< hOu;+UY%^Sr R}IJr #w=3{P/h>Tpgї]Dd<7Yxgp<m=T+PN|I6YgEǹu|~5R8y߳l3uU*.htWr(a>>uY3˛_V-jRGp+V.A ~\I6$#:}ԣ v0mvL {~kG%#}ro0t}5q!C󣹁)N?] 7g67 ^f" u)iހ @$"4(noFUG,a;)Ipa|?w55,:,NK3F+gSSbZ.&r5Rw/1N-HU^ YQ;D(r$M#[&7TƓ&SrO%!s]@t^HjTN2j%^PY }2x#/VKk cA1{WqXp)$>8+Un Oj4'0bڜ/:rU9ܣ]ɳuպs6*Q֚2 qb7N@PcO:%|ħ1~s뺖PD~w(FX#y/'9=bt9lKl,6bx]*{s&tQrKuZTĎuy;&dDev$]A5lhNqSxs0[_lKs&!۾sתӼ< 64%E݁YD1 "]Ͽ#*Y|[fI؊un endstream endobj 246 0 obj << /Length1 1630 /Length2 17155 /Length3 0 /Length 17993 /Filter /FlateDecode >> stream xڬct]%;ظÊm۶mۮضUm۶m|o>=Ƹ\kMJ(D#`lgh"jgL@K 1tqR㐦Q41s 98[ 8pL&FFF )@@FAEELdaf jbmgocbQln06kHȊdUb&&yCk # `Ҝhb 8 N&FL܍LQQMm,,f{l5v1'rS%dh/3oTyalnOl'j_Kc;#J/_X&c '{k;Z+ ' [̀hbfhlm/?:KڔoL#翱,la [S;.s5qWIZ{MLad߱LG-FBX[%c` gҀ_LLo[lRCOKo9o%W56q5 a/:es #+H`VO!AY2;s?0v/Vv #;7!FfM1YnzU?<[#;FGO?j#Gǿ$k?{w#e;# ˴tZIa^` Ev=~iaji9'^_,-\bhR^礊@IH(AH<XS/(g_8Ov9A&MٖIy/J>vÌϒ R{o/_Ė xLV'L:XH8~,w5DsQBa!7MWRv̘dSozaf[ז'STU@Ko1r%02PLyL/o"߾NO@B~!P(*tT)cHbTa`c*l}wl›ubBc< ĥ^debNL]3`P>"*:,S bZ8ȀS.lӧK`8zCqG\7NUND42#Xn;ӏRzCW$OǓ(8vVD,($pHxJC#YOAiU ?t?[ճ1tV[Y^y&ZXYc=I<:*o>iwÂ]YJ讥}G%l ]xSqahL8s57_SU/IzօTL(dLsQDN 'D]F5/>'yBViF@1so S*VCd-(%/:YZ nu22٤-@.Π켔?M^ajJbK=2ɜEM MODa}~L'2r[ mMtoXZJO.=! xoWkw_0)-F=tuý}"ƻFtꓹBHH=}!zgh|MutPJZGWWj(GdboQ2ʼwjkOtON{RH,on)B4wډpd؅TXe۬>ҭu+%&HmkH|׋YO *Ń7]K4>Oo /PG;5} MïP։$R/LQ ~N+!VRIsAY;dR5n$:s d/uJZ&M/[<4謏2@ϾlvC QM}Aw _T i;#nyRYCnymެ7?)úS0?R ͕%_O& gÄ>Q*&em ?#e\sJ*>%~6 Qn޻ߺWj|T_y+&½ [p1|W%j~8 zoXj*0x4LZ1%VB0};l+"n֐3:-Ylۿ'CF\X4JWʥCy&cQ&,QꯘQ^-{ff"q0r± .βDVkbrۙLiqp4F`Ryc8|BpP~JTx|[Z9[5vXrd#p|4!-\LRrySdhK&(6|` k@1ᮽ,o_m#E'^EfOV}1/O"<xѽ|xxIoZlKBԎ~ |Vݚgr8jBl7\Tf7Dw&U II,hRfe*8_cy.<|墼78ݨPP6۱[$Ly^ל^ ~Gg=Ab"@kT9O`~@!)򁩍jE*^ ǂk=dd~gNbJ ]~KOlrEyDӫ)nnfu N>/=5!wשh.d{NJciK#$o*fIQ." 2!QʽͰ^ֽܰk{ɬ$ FxP< Kz’BI47_=G(ɆZvFFs_tDO?3O2^d*z9<zt blXdԵ8xoI(',gppdfchrS屘ZU3<-Jdu+. . 08 M]2;]ϑz$U%$XTKLbej9Vi aJo5ͳ(d7rMz#7F7so >zd^.|Z:}BY9 }P|m}09*z̽lQw".zN0ԝ"Ilfvg;T5Zu3= ̏u\B>n14a1Pkdzkc.}: ;dDO}dWFѓ6ItlQO e)x"R"-w"p MBg{tpZq6/ht'J|@EZZܒySG^dų$6 `ֽU,>7^-ׯ6oF7 Z`TTt;jGMgnȭD`oշ 8S}z='s.20?\3m>"`!*L>L7k#kJnـFH+F"2/ho6w+0K+dRfual ֔ g O1eF|Џ $, =? Je@!-Ԟ | JΝssT>  ,NZIժpn.]Yε:j8+kzPN58(PK䉍XdTKt/xP3c\8J̑lYVbb8!+cq6GtS`T;_* >Q+bPz?fRU\^?8\Vq ł;jB4 rU|xCSSLr:nȃ6Y`.1#Ax:/rt8vQo+Ll#3\N˟I3sahHєgp͕=<6,Jf..|-T),yS CiYF$,Tk|ZqB(HW>{F¤W'gStu~"; QjUq A%7ybՃn-l=BO؞wgFDfTEt* ?-3Z|Jg SkN%ʄuv&jvzit|HHJS! gj#[kv##崯(&pQhMKp{)6S엨r "Jq8ӂvew%7@`f2qyƂ#=VBk\i7a/T3 {#_eWyJuڎm8O(]Tab cj4zJ\R-PJʛFQIӗc+Z's@w'=9"sFx=՚E㼊9?Rk!Q)eٷd_}+j8:V}Lˉ#>]1z,nA~ʬ-~_Xn5ӊA7ԩsVHV`r)Hi224 *>{*Cv?%!32 'UJo orI`wjbgyhNUT4OxxR;E3>6iBKUFj-_r);l~78>!֮m}K^#7I 8mv{|,EFP,Dbv>\xۄ~A}mb?EEU_%Ӗ 䥒`uԨV?+ S@œ\F*00Rv"ڶ:F!1xnIoœ }?0*u* >t/ NsS) UR 2۷-Ԏ^S\UmPWBqlRG!񏠵2SSƗR+,T¦Tb>\_q[M3DJW֨"[aUp%%|P "@wŶ:A)}*7'䚥1::.bV<f-=tΠED +Z"#k*3R8T3/c@) D;A7*õM]JL !kPM]^1<|-*/4*-Sx󝿨ÖTffqMљY5 vqxV,⤟cTEgL $94ϑ" kĎ[䠷l0昧E(ʢkЉ(rۻ\X(-<qT $` oBZ1Uyi|;Pڙ QXHi'OB^boཙoyښb\tmV[qcg+JFT+W+ĝO @Xa żNc-Grotݜz]nB`Lc& ]w6s)R莜O2^%17ɇ(oU$54+Z:~h.p6UK}CDC@Z S .h:iaQaHЛ@ƘB0ЅM-ՉtF߸<Q[o8\U=nHz,oBv}5l w8QO0DDG͈7PeL/j4쒝gcב9XWQO!BARGLj ݧS6s2M_Ӽ_ub2HJ(Yx-! \ 5ER͇|녉vޛ9ʟN!@1,zM|͕xuGWa Ojv7l_bNxsU}I gө ƳŒ*.QOUJYmR{!V6N@lF=L7?>'/=!seC4&rτ5PKCKu>~Q9jd4vko*d\D5jHի k]-џѺS o5"<<zQcҁxǽgA8MөŽR5{O"`{~-SSO{:}L{…]32^n]-c]iYQ)K6e=F.,oSkcԜtk6ȸ S1+Qy=Zruї!^:08Ikm w芧i ı¼VgːX/# UMOVȢB]uhh)Z|mHM&ݿbY)= M ^bpCnkY2R9^&ɡ">|X xsgP 4b%Mb#a|]x+TYjv $ݓͅh, zh>69VH8⤼&? ^ّd9PZoV16NѮ4XSfˮ*cq*VK+$ Dc%GF]12S^܀I Nk#=. w*gh+C '멝s[@H ,!ڟ,i(}H`t[={QB8ڄ d`3+9^ 2xDc2\f@K=K]ݯRuyX轧)mSvSsY;EX(JcŊӢd?mu@5e|hяǽ5Ɍc#P$gyz!4@1̟¦Gig%48 ZZ&N :z!MXi?Vjbڏ! [8B+-sJ ޝ0i&5a5b$Z"U]P-C pzM<j& #'Fd[^en;;یce:MVcQC_~,\'^R}x$Ą7hŒCIrZ Ӡ5|ݥF|exQ(. F,R<@bJ*>QIqkɽ-̉c?Xk,|!-~}[yak ANٴ$OXb[`3AC,glhɻڝYF\X $i;T>Z*-5oM4:3 CMN{6Mq0kqE>4%-5O(vLɸSGn ch|vc5PHgi &H yB@BȼZ)Y!v>?ײloR8al×Upp#  #$ m?\Hzp_ q2)յ/vidzä,$+]k4[^{[b/PJ vB0SsôkU~:h jHJ ?7BȮT<@ a yzg )OGOIOkA)" -\FR)J ӎ*At~syoBCd!3:i t+oIH3'ou)`,F!4|g~}D_9lkeh\JO_:k,O >(ٷpKobDX(vn\S=}8LeC{(`;Gz+k]hPܐIXXoR/ďsy3!+@{gc89s.4a\  ;KPu=4B.a+[i]OǦ#2逈smY 5ݺ%+SNcx춭/KM[Z5"?t/\lRq|[MVڤʺcXc~WmD[(%@cxNU?Ukd\1вAT)olc;V)w6 <(!㇏¨Cov1Eb>aS|=>y; _Orr_HA g:(!Z:RX6X0n ޼:dy5GLIls kNhS5&a^v![+{0uJ_c?pFNp?&J~'pw'Tʟ,~X;?+j؂|nKfN7n<|k!z[)7-C^h; RCKTŌ|Tص=[]ie8hTH4{}3}T %BF_ZSmogNUY՞#W&0G V`Q9Rb0EkjR^K]O( q(@d0-9Ղs*[Q3[o#xU%ܑ[Šʣ_Q΢WU! zNbwJ:Dubփx4Q35a?ab5bK~uzn f j[ܯ#3MbZ _- I~lq§!]@Oh p &b ǭJf#OB&I'x17` ZƑ||؆u,Q36ub 䏡`!K[/OJbޜ%[]n 쬗./#N} f4v|ԃŽZ>;$|Qc2 R(}p~_!A<"OwEv/ PR5O~>Rh}StDA@A3emC+*Ѹ}Nͼ!~ѐ;8* 4_g /lPQsafN}ta%\4tMn-+OĹ: Xեt#b`UOc #~ŽU"}5:`e~>`v@iP b<GaGTW`A|=XebX bE UZb_J?U(Ʈәw:!i(Qo2c6^okA?/8|ΆD@Au.L(2Loc4h4t5OIx PUf1l7n;0|ƞ.jBGSEL"=R.N)g|+lΕAt˦!_*]MjxN;/ll" =κi~,*?WSpU(TևAp$ KmG\63Fa1%I ">|zY-xKxF<& 7@~~6߈AT3 wAY gnp17! [nNCuwR*(p^_IJѼb1E>ׇs[ Pƕ xjyQfͅ19vT0=>df\w%9x+jo[Dݼh{uj !Q#Kbc/&mMXwXI„{Q#w^o٦TLGVȬh'f&cFiUqe+KojMTV lrZe Io5Ɂp -$1o{ɖT iY(T0>PDޖBK]^p=H'#O_dC.y!XzAկp)vY6=]]',̝RS')WiZq;9Ӱ[ ܉9aAvx"xٻܾRثMXo zF`tq1f8 ~1R ɿ;NO[k1?\V~Z:Cx"cPnGy3= k>Q1F+E=Ndܵ{$ (fE1ٺde0PG$`A2=/p~K4WZ 2bzBafCr*9 q '۪,鳨ͨGگ\XP4/ EZ6GΩ}/6N}CuBf,ZmĈ鐕w#tK$@u[g$GyrE0M 1J:ZR9X2U eAër`|uὝwBMH^}2RG$M@njS{voJ~iRwEw8eI|Qo&Tw1;(.U +&+QRwB0N|^dWpmqPefr>e`~- GieD'/N`'TWwIV*7k E&v Ab*cm0L7w&C440>!(YxFZo.s_7FYw^H\yz  G^n7[e#c_6_Ho'iLt6b,PNVN.;)u65C~^0Jl_D]ӭBµ@䲫 IuWdj.~\0d5VYS۰Nsu<&J4$Hƃt]Ph ly~Yfv@C*Ի]ǠHi㷹GTSIJ/Dzz)!t"Hc>5Bd %B!kxB|[sy3FEx}p Yɺ ̂ՃԕMY6F9Y"@ē% nk.T.ޗWK|g9b0\]FDnJ=9ɤa(Ms V㝎dQݤ=v18шnB'\X.GPVNXJDGX9y.`2Zdt,?uz 8MUӬl \jqF:][;牕L9ga$AH]kIZG2`䞢;  )4C~Uf]CYxڊm ~ɻ~S ;RšlD81U>4;Ӎ5=iUa`Ҥr5tԸ<Q>0m@Z-%-$%5W-EG>< ~tĪK>=00h? P!r`[dk[;\dDmxS!ߦB܂3* {&1PR &d\jBk/S3q2UL:"x0 mRqJjۯsLArgݿI1l*ӨûZ]G%$wf{Og1/pՂYeUMr;@_8)<,rµYnۡƷvasCGsS%%EaE#FVlx'`HF;5/ \y~_Gv9!B[Wb"1\f36liD]x6̫95g**ιפG(o8v@]׋C;(6$4X򹯝Qb ,]t`N``E 9MhOw`̮ Q&MNgR23a_+(2a9€/7r3*μDNJHXSi|Q9|VМӊRtro əgbBw9-hgu{R}1>یAd& JGFRsbvaOG66EYXM"UzF&e[~rx7t%U`)>pl[K2 _;LO\CgƄϪ[ZV!oAoGy9mV=BQ:u(xCw`H0/:I&>J’9%kl?e{iO237JjCYg^M9%b8aZXAx}Ȝ5) }LcaN<,"p&T#+x[*UfStF^DS?*M:?b" &/\N9 ݟbU s[p@_.`iAq Ű@NZkbv͘A Kqf9$ˀ (x7Q;kl fth˯iӎZ-_aKL "' ]. 䦹 N5$,UQ,؋յfGBj ra3m*:00<¦N=I^i{P?8ڠ:cW케,KiMSXl^7= ؈t87Sv1^HxEٜ4o_xJȩ~ nãXr٠}hƲ~n [t}ztAI Bf]qIH`}D&lꡭp 0'/I23"_`%q[pqO"` yE,y]POu?M.UoY~NrԃqKӯ!܋+!*O# j_ (g6"bTQ6,ۀB6.|I UZ|ޮ(2j b dlb !kM |G{2-!M "Un 3t@Ϗ"@5"6>%1QQ΋lzFJ+ 8GAS.w%L0mumBD~7tD{dNa7*Xgj!!jSlƃlڧV 5RLzqUp ͯ)SۚGƉa d\k~iBcMbEznlfcш+8i (n8BAon?XF=F 1}8k=.i8 6U`Kg__$XZV=5ݓ'EV!( Lߦs4Ops呀fY| VJ2J{u[~]Z-9g1G7,Lq@tHEHu{TV_Ke]\5ڥYmd@6<YM)G)ASmؗIA,g;Hy4 wM}w>?YNGћ WTP@lepv(v >> stream xڭweXܖ.Nb%Kpwww !@B݋w)RýhRX9g3w̝_^^w$Ԛ:R.Vyg;KupvqRwRe׆z^|2n , Ak, 02.>nP[;IOۀ_?WV>xCm /_{}9@aG KL0%-Ϭ(9۸\[{ qALf% b{ `'+'k{wjyGGuc^ g?_|@NPGo@CEEv!^A.Pwy7Z l@/}ۮl qs:C^v ׿avP!ASHKG.YvǗa Ee,`>gbBiio;v [_Rpqpq_H|rOh.Ir~`7^/WxCK.`PLXIgY> HkYnqaPKo`FPӧ0i_>\Y{!g !eؙ'T s|6/}BqC;c, zEwА@ԅGPW!qh|tdc:$ u* Sz1ՠ?E˗qɃ&~yUYD8fyY4fsd]E!Ϳ*B =%e+Hv#PrW ߵAx\w k> o;q[n,3՗al*A\<("rl 0 B_=>Rx)SRm4p/Wؚ)>'A6/i ,FðNdL5qM.4sn=HFdzCƒIv3<3y;p}j"x=,)J l+cJF*H0úWo=R\ďyMGnx`EHΜ.dwuOXqx $5v؊ij,Gl4tl>ηRWi0> ^-aК?(T~D$I7l]q1ݏY*(cD&DOԝSZaqpl4 GY>N~;vc%~L&̇u:3fY?>Sc IHCqxDV'XSHxHr[#X;*6QA7JҰ-6cd/(+q,4o}i귭? CV&!W ᴚشR.9g%IqbBSdm]7az%?5n )L+:E\h9(r!1`vQV?9rLQɝy6"(MrЍOz'~0V616/޶5Z}etzH%YHs5jQGnaq<()'zϼpd%w{HJSKM "M-ilG px!b8#;_Ȋ>}}j<#wjhg+VWWvCD|mZ}peg ($J%"s$_rZG*voW;DT_JS8'N+ &XV/u IU?X5 {Ta" {DzBZ %T١/wu]0J؏uCI@fYbCBm_1[/]ov<0q1! iQǷ?:_>tkdkCAG UJ{K$yh|/̯߿5 b*3VtӷMwdg/6uަ!>d:?:tV;OriYr: LB6kFf+ }\b6J&/>w _0Xrs6p KMǝ&u +Qdd]U @L>3_jѰ5b< e^'#Z  PғNù :d;qTTڎęx2ґ m{B}52yV+Y fa󦧖wJuyTkdJ I;v%)Ƞ1/ĵHIJ|giΣzX&.}T_~$aѱg>|Vg{pb'=V׎h5%]ԋ̀_6xeD?C]cv&_bi\O˺ѰnOd%o-DxXz}zyP]4*ZYK]۩;_?l~iAZGU-jVɋ\ lrPU6Aoͩ}ܜٙE=̓5LZ 'fMNҏA~sxqU%O;⺩&^$K OnZC.*uvZY^, fTTsb6~^J\U7N# #ï0UML f!BhQt,^Xj|Mv];2k{~|GDW|EYޒC*B&!7)J@$s#mfeZ\0,J$R.Jݥ;/?u9 SLԇsF#2b 7ƪl2MVqq82R837W+QE:7zHco :Xj0R?К {,%일!U2K UӠT.>tfE Q$m;1ǟn 0;w/+ekrE~>ЬQ~uܚU)^|W0WF^sNG%ۈcpccC͚ a=IA2hJ4q; ywYӣgjU"~}~J;:-W'Lџi!P)8d}0s\2"H<L&8*-v4Hђ;jd˅.7(+b#CKCF&?z ͖Fh.omsGտA%߆ sd ,}D? 1^ScDϣU6K.6ʯMa"5 և0+jQmHQJ>B [$Gu I눱^ە7<=02.k$ ꅏhE$e+ɝ.g7e&6bZx'#y؃TO:ZpJxFAO$s{z4շ;N#^cV宿bgunI&![‹O?2cQdč3D͢(6?P?pK`KYy.7w`n"7-wp3?7KIcva =ϘIxu>[UD"NՔ*yr ^~q:*ݟ{ \4,Gr6Yp(Z(pcqbG}=KїUFz:0P!->fGNqi /G%ɜ4mw[s#e􏩥r}U - ˳e=~B/FWH09S97g&qcu\TO_V)`S|? ?QG:8%`E%Ri(T/ZBQ[8ݜ2kFdEmu$ŔJP!m8ÍxW/ Vl 'ē{ڻEj?b5o*y-Mj o̍:6i ظH??< TG>{: 6:]BPMd1&?EFCLo,b]k\ppsIlr? M,]N;f%Fܼ{NfXC}?]K+|wR %ilܦ黇Hf>7ys<JCbAÎď>FNifsVedUj/Ooү`{k72Rm"g~<'xL Y\C/'`/)fb N7K/cEy2qȧzd(~2bK';TWf%->Ԉ{ί,L><eJ/~(rk)ID=Hrtkk6yv=qY4v!q|DѬ{u޼ZO4v FM'ɾYP WXVp>B+"U)zϺs<$6Ȇ1/hv! WHNkOY_0}}ȍmvPzWZf7W_SU&AqS̤?W,Yf!9Rz7v킉5i5[PW[FIxMg 9W{l?V[4muzkLS[hqZlok$Tjz>^׬2x):iK؝iBIe{;=2 %62|\M9 6ّ} Y݀ LjA [#fwT;~rz09BRg_iLwMc6BP<;S3B8hWwe<"i4dT ֞ AC W#3xυk1R[(aA}޷e)!eHQ>Z:/{k`Q cJihqk'3H2D\e:xI:vL*MUŕ 9'yPG.Na@0ϔ4A^].*B7͍#@ы)ꤹytPMwrgvnGs #ކ܀1AgZcj'MB9'ћq1ni|}ꤺE{")/ś҄(ܳ>p}:hzXAQ^>~+I܍L\ :to)\'G͇_R!"9I!iCʯ[x)~&^Ow=2_אR[k4~:zE6]!! a2u%(dX´RĂMa(**5t)^}&@O7sc"#-<Q"vEms{\ gػn bOxWqyIbWK&`&-g'8h2vwtdSTWJFPm}2H!& ݘL*˯?{7s~& ^䠇;xo2r'Wo^;Oi F%BGryG~ r狗1b[6uf mEy+haD$TʄT'Psad7]l+"Wm_Esݨo/cvNNQP.7Q3עJ_# u!q=䱻-9~Q!r~uS% +(~Ij=Dˢ*,ttHǎ` M{FvUɪ v /H!mO"Y!YpzY]{) S1/>u)$N7RdJ‘GfÍZmuTb2f/}Aoޤ]XUI;/Ĺ2;\.N%h;j i'XH~_0]l2g'iPS vA/^8Ωʏc/L]ӑ+Y[Z ܶ?Ur]4T4ߺi.Ұ<:H3d9nmiB 9ǵo/h ZۡZO"7+wcGWsG"wB9;dգNO-H(hF*đx4) Zulr+,#BmuRiB5is,isV3ž,@Toy,Z eK*~H((K6jI$׈cQq&{V<Gޝh XJ\F3{驺@ 늸g"e䋳j#'ƌ1#T>cղG~%Dh5"蛦^L=m Bp}LNon]:_tQ9G첕rՑ\xRFFˠxߦo<`& \@e.pD= Ⱦ %G8+2nz~Vɿe'hm/CF53HtQ8b276P?='YלLD-4 k2y ӊ?Yf);Ϊ=z Oa8; s0ym!ΐݾPRHC4[EmH pVp ;,h4h&ҩ"/ߠ"/)GZ>,d۝JL\o!=ŗRO,.OupZЋoh;wogTPVL&o 2*J.z1g*Nl{NgcYU<;`ep)Ί@_/HgMkKy#ЊF(Jju3(p4 za~u8 +_=nڹXٞxE6}}IR/9C{I*~VYv]V o[aIm(.eb茠B)m _,XZ3o,{@IR5S}9cҊ!dI? OVsw:S[޾ٵ0SZ]FL4 xc+(r.-b JZz-zET><%lњ^Ӽ28*/u$=Ipv 5xL՛^y:(`Lt˼wD63( 1!4.Gog'6n)0d.$͉H [U:2.s\{lnC{7Asq9+3,q<\6w舐TaWÑ W4,!ʑZ56 $˹R!g܁쳞p =J E)XՃ_m3-r*u}p<6K%F&ٲ!'^G endstream endobj 250 0 obj << /Length1 1647 /Length2 10964 /Length3 0 /Length 11810 /Filter /FlateDecode >> stream xڭveX\n@p;4wonqwwwwn]kp!3gs;?zWVVU7  (CY8X {3gu2D@Eh"5xih$P,e  t)9! L8x8z-u&&I2yS h_?\v{  ?vPk dH+e@0U3;9@d;'?sWiάXSt7:b8Aί3 }(۹XwBNW W+*lr^J#O)ΠW5bji1wu0Z) ݡ2,@v_@ [+f NooV dE|i}m#/`Kr \N__=𚄩lZ")C!3YH_zwC˸)ڿ6? uјkؙ:Z8 d9Y濫Bl +? g;B5Xڽ^r-:Ndn `ᕷ+`Sӗaoƪ]p#?AIH@^,N>a|GNnGؿ8uV2:?>4bWi@M.NN ^+!݁ȫK6YzI)^FBZH_z@K]kӴvS_F{zR$>T }|LlFehg:^W [oyٵv&ԍJ_H;\ q}>vozU_tzFt@7862[N|.1f{lh-29&] ᅽLb{NQ;8yt"0K~N2CTMĬrМf(b%Rauh\, Q(NTA+.Sܒ/ABzs_3ty`!o0f8;9hp(ᔗi+YoRPx:߄̽9dZl>룃,EsXf!>.PrC ]TլH*3=]B,ѷ=.洀^ǝH:pA51߰+X@ t >',wjQ(x)o^?O<+@BGn37D̉0)V&4_=׻[挋؞+ڤnݱ@8ԓ0K@,/$V6D4Ѵ<OKY2޵2)sgR[,IS17dZ}z#{e%gN:š"|p![->ʖ?>^t,^6 V%9Mʸ 3Q3FMٽO`\78=+3w^g*"!7"12lJ^!skS4 ة'xE?[-m*p` $> Ye}kUn^ñ[d"ztO#:(=gn2 Jv"hVFJD*:+Eg$g" wlOI=b5z+-o VanǎeЮ~E]Щ(L$p\-co-f1-&w ݶ12-$><8!Ê3{<&x&Ûs%E]J;2ne*d1EQjU='W2mQ\cLti;B;Š3}n?L+$֠ng{uJ3Hl'5R}t򽤁[.9͡|6^w eCS3!rT] 5,W[V\cy#Q7 Eȼ9Mav,ܳHw1X z\ 2[`D߯SjX%PmJξ?Y ir ˳ v'ݱS`S@p28_KZE= CliN}uuճI,7~3EA֯B/~,mY*!]m^p X'óbu<\%8mkQ*$6_`=ΜXFF; TLŎ."Fep~aͿX dx8KQ*?qgq5EF :`,&{Kנ[O^݉^YvpR΅ER39qp15mXw8D9k4'Ji<2&9Ye<\O4]tHٷG, U? D&긓Y"X*F)'.x)]O!^?LjJWoQ}Ȱ?A lZquW(k zo> fιʍPnbS=Z֏x(-oNd+ 1`N(.~H|W,d ?$vJ^O00*"Qx ;چtk.sH#=v c/.KMMG w֏9Praϱ-nufşUB,gZ PI6JD3U(K{çRDaWq(WzX4{ ںAMi I90 y)Q'ʹvS_HNC"wHڌj-L<; j]X SZͯuSLj('e4~}MOOY5~!$.x֑$H>!VjʒK#*[# ANvdɉE|]l%Z |Ou/4`cm"yF"A6-*7{ۆ& zbWoJqh /m(ljլ{H|crf.3]Z/r%%YF,I, Qu8\X 6NJ la3 v,K,Pޖ{Y-_m?;ĩ[t+? Ed|vvcDuCxxx7B^E,:n;*]U@bֱDM'֖IPrLWgo6|Kw=hT6I!?PyVKaD-xr 3UdȌH#TJ%(vߔҮ$:~iP@[4$R5ױb}k,YlgOLZDfv=WYI= ݒsDqGa0&u1-pa?'C{ I DPZN4K^Y>j:DawZς ɷ^Q:w*Yqr-D2t aT!(5KLQЯ+-l}jOÉܾ} [Q`eL(8R59 "4z㏈']BSmQM5_5"& \+Hޘt;2:3L-#˫wi2ܝQ "4=z*rr˄',&j1lGeqnPɋW'o<}%uM*.TY)^k5!uKf__Kͤ㍩|''Oc1LRF;;x5V(Np0گ/_?9وz~Q%=Oscq1@}+})IG%P<]7 !Hz!n;5W RRt/s"SO֨8=8ؙZ;<j%'+ة MmuPY)l֓RMc+d}9Rk ꭈPdXc2Y-5f-bҏu=b3]G'i0ǽ^ucw$$nbgOUv?Xw,wcRǬϊ) =H)Shl"}=J?IJKu֗ Tt%._ \nHBJ{KՎٗ~1LbS{@k: gXЊ6v}PynCcC8΄u9VbEfUa͂ZGk]DvQc-HW?1\rL WW-m&*-{ Z&-PPsǶ/ct8]%QLV6+@^ " 66 ɑZLz]!ȴ0aiF[thc1@K.hlKu&{<w -{| pOľ-5a4`& MGjdwwe*:;Vfr:x3İ ͘wrE32NNBp;Efc@>Ju/@'TG蝮ߡpj&XhTu}(tek<|ݚJ7 f\|B`d}mUD*cꂱ*v+q.'כe\h3WxNIXOH+W8:,}E 8;* k<(lTa?Zg .>{O;8}fo:rŵɽs0 \x=纾Rv%7~l2SPp%-7*JR(2VuG,v(><Xۨ``uC O?D, [pTcOpmCL=$t &輄^?%0%Z$Q|[1a'h=¢E"2JQ6B].L"xAOѥo/n+ERlAS^xQknl1'?-4MNl*$IB# x7#qׂQJ?B#&'m qPlM % ~g8 (vIgs~/â.!$͛9}]Rk0{+k?*͙Hij۔HAeo\tTtF+oen}z ܣ/ dñ<a aɰvIfMl "ņ7TDygI)R\禝nO<n{4{/PhJY#ůG" H?+mK?p?Oy|&"w&*|Bx@("7b.U.~ "vjp+eDЫ5TDMP ]Y5YwjqD&`'0.ō!TuzmxsEdt5įBp^<16eFyUf+R`>/}9~ +B{{J2;(ϐ^,QNdOlЭU{46#812Xj2s/fCTPB%Y0+#٬.}*mt1>\͝}$<+DZu`;(b$)%TgYmG}8[hy?~(mhYHJ TKş(Lɏe%2b`1$uS;jB㈮f 6*IׇVg50rN/4ƨyhX#Prarj-hNiA+E{9SY4a4ĭP4D\-WbC0Lo5̗MB5:R*!g1=eMҾBJAU:? /[P ҢEtl Ҥ+9m腫߹DJ@? Gm +[v=&'ȧ$k8e+;@J!5|ãmS[8%%h0rMsV®9b:xE^&rInV!>4pBKl]$?y.c%N!"M\gthUc yILW="ֲNBri\k.*K#P}\˜tk2AHp< ^7v3,~ Xƺ883kװt Iۻ;Y(i )#?ٕA\y^3<:޴2Z4MI&1JO. ",8'ظ/%k9rÃ4O5wY $:=BnaҸHwCRIvUVC"27 мWc_viSS+j<( JL$99z4{jwWY⽎sSZ /Zt_/b2%*YX 0yxm= ?kQMQOerܵs?[G%aNetvN3QzEดfMkEN*C# ,2& G֮eA q |~ ]-dV:ezxv7#]ctI#2؋mʷy8GI{#E_2\G1 ciU|P'5UN=.FM|;npg!4f8PqyV -MT` sG0ޓ>-qc茂)[+4Q*f 1}1>SY.O' |Б=MκQĝ?~!sN;6+z9uD5ZpiJ.Պ#g!䅦>p$Qtݶw;6UJZl;8^&j4}}OQXprU^}$`fmQw.4[ct:'ݠ)DΠ^w1V}}^Dnˮ& qN5Auh$"YA*RR wI Oaf$9TcP4>9oO5`k=2L9)ԅ(5U Nx9l7:|+d(a靈 ҄$>Hj!A"nr:}L}.IoDysKGoIz ִEouttWjU:VpdOY2e\^5_.)\ERoBڟ$BĘ{KF"z.095T(Z<ʓ,*4}RT=ۄ34fvTgP.YN!ꍒda;Xp?l/Y[<;+$>VM geJynI(<]=,F dw ͽ ݽNtܙ/QҢDevA"^ߩ)|/^o~w,W~@B#ٱ_ۼEj=bƾ).0D1IߘkND4( jyӏe BqStuWyÞЏΥBGIDY另]NUg岤}Dҽk 'UQ}9JpY:-Céi(}m o^knvu/viš7kkXqJ`LkjdD{P]gZQؕSYl8'9>v5bT < zE'p#-~~6.x .l ry!ʹ(v%O /OKcqs`]zVO&G7i@)k<Ƕ}{.40}ݕ1h޾# ~9XOc`r'DoFa .ck2 [t{*;[<<0SC. ذ#OvN&fltZe8K"B=e [||Θd;C@ި=I$GHǩɽ! "ᡎd JT[@ƒ\""6(xjD/A 7ogNvN`(W̶qfa? FCǨ~<]5,j3f H,Bb]DŽ[ 1x sP 7c,`v.8wôRB3;aѲM^6 ø؅Qm9_>m{R #,+_?Rb:i\\ݮM!GPSWʞ4n( BKEi`Ӫ0Mfg)tmE` endstream endobj 144 0 obj << /Type /ObjStm /N 100 /First 863 /Length 3090 /Filter /FlateDecode >> stream xZ[s۶~ׯc; L3m9NmDZݤsi,&E]L'! r| Xd*bBP1Fj(`2 אE,SLI S!"bV,t6eP-X,-SCL YL+fmЋ1EVE-^@4a ;PYJLG2$c iD1 wDz&$F!-yJ +h-H , ࿀\h Br <xH1yI2IB#(. &D4dm6:% CJS#=Ll5i8aNa S7$,!T@$)4$2)Kh`dB=)5JH)XE;,R mIౄ2v@R$@KQ"l4 x`cZYA!kc`g|lLd92hZ2VCXN` (BMRWD'!U&{,BXb vhPCU*8&#cM'ËtƮ?0~~H4㇓ lϒ(?d|FƳǔ?$9~NIwGݼݚw䮕Rnzs wt<ˑ_i>OiJ{tevMlԗH2D8B0;5B_>Q)l<nViC$:H}c&O(P-6 8mvM'+ /zYbV8c-(k/o6VV ¾Pw]V8N/g݂gW>(.aA?6tяBE?)']ӂ~EWu y_H64vQGF &ꃥYl\χ6^B[_Fq?|f~}4z(ܐWӏB!}2Q_oQJ1Kn[QU:sAK>дvRtih ;zBq"$׽Kt}+7k$α;;",+a9߅ ޼-mrz1m ԝ?[<Ҷ #l"Z^;ؔ^S:W%.7ˌ2ע&VVU~۲UϛSUM<<\X xcp=&bGs<=%a&tʟi6gA,v]l}GO<TTii\<g()q̲a6Ο03OD!i4t{>=?i>?c_g>46ØOdiNq`2KnG|sOYN}ELg|DŽ||4?Lf6a;=\pr{/2AVYlHE # 1;/x6V??4{xdt"NH?(zNX]n@qBQ(PT+=n6Y G q%Njpo~;<}w9qA! ='EӉaMPMΚm~~w|mitbwoi'h ~k]XN@(v<p(kQ 8!UeO+P@~TbS BoZo+3l24<X~Ŭar`܀__V,W)}۵"鋯0$V]n^-=^'y~{_m}9~d|FǏFMf|kilO'\x'ooڳGEN򧗾ӷm{8fzp;W-5 )pR媨O֬s94uifO1-[mtz| Vʽu-k-m } 7[NhWRlONiQCߗ5/`%.joVH"UKY7gj&d_ a(Q endstream endobj 271 0 obj << /Producer (pdfTeX-1.40.15) /Subject (GAP Manual) /Author (The GAP Group) /Creator (TeX) /CreationDate (D:20180323231545+01'00') /ModDate (D:20180323231545+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2015/dev/Debian) kpathsea version 6.2.1dev) >> endobj 254 0 obj << /Type /ObjStm /N 45 /First 378 /Length 1561 /Filter /FlateDecode >> stream xڕXMs6W$;L4d8'9ur%Hb# Q}$@$D'ݷo%% b Qb ӈ80 HIXqWH`%% qR 8#(,0L1q3 0,aqJ[7@HA2HD'0A%qQXOBy@3,YaJca)<@xT@B(Lj$" B$)ʢx9G$ =5 IR@4e|$էFRVGnuuٙvjJ͛.2G [Ǹ{+%xͻy-ڝ5ItGGb1nρ,bc ;,,s.Xlɀ耵c9굏5E[Љ`Z4 GwDS1D:Aѱt.n~.GWlDt]I@A\$x((6#R&Mz܎v;zם.|.An6Ǘ#ٸG5axBlXq4 ´,I{(_|ܟ&vr;nܮ^C O=nB*E-ZZނE坱=XhlXXZoPK^{} ԣq~,kxE{4>GX?%ab7kF,SU=Je]S^j)uZ=vf5*tUu՜vȠ1vj_g"l8uv|fO ~a&&יΫz/;}}5hX9۪94')$t-G%KXϹ|L*Mk@z:*$*dq iA39x2B^d4L'"Ù<pYS,WsyUY)+O^XqGqhʍ9)2C$3t6Φ )ӻ]ˋQprKr!޸p\=/9en?۰zYŭܘ }:@llkg}@+Ӫ5(EZVWCg0նfO =*4LKȫ^ݩoNk{gBc2eԇjN!dfUy ;| h(inVl@)Qu ʪ.wVdj!f!ծ?xfegXKݍ^gM" o!_eQ1c'Mc HHo3*B..W;T_omgڛcٟ?sJGW_>OꗫWRūޯQ BJV4Х endstream endobj 272 0 obj << /Type /XRef /Index [0 273] /Size 273 /W [1 3 1] /Root 270 0 R /Info 271 0 R /ID [<103B346D2CF76630195525EC456DCA54> <103B346D2CF76630195525EC456DCA54>] /Length 647 /Filter /FlateDecode >> stream x%NQFE'h@EQQfeĕoͷ1x3&}IS~uߒYܬV܆zƒ@tPm&4-l ` @W##('9p\ /nV_rNPEV~p8 zA]Np tǀMMMM8t@ͭ;,syWX}p\fAp @uT\e0LnRk:n[`L:`9'=rAXpm{ [ߛVQϊ5/Uzs8 c#P!mߢm`pWd|/"0G96 Č"PE9 ^X'g &L&c8.b.vGnpB LGM8) 2: _60!yY-^j}uVh5a^~^0` ăăttLL#/IFK_?U. endstream endobj startxref 139893 %%EOF