diff --git a/FpCategories/.github/workflows/TagBot.yml b/FpCategories/.github/workflows/TagBot.yml new file mode 100644 index 0000000..f49313b --- /dev/null +++ b/FpCategories/.github/workflows/TagBot.yml @@ -0,0 +1,15 @@ +name: TagBot +on: + issue_comment: + types: + - created + workflow_dispatch: +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ssh: ${{ secrets.DOCUMENTER_KEY }} diff --git a/FpCategories/.gitignore b/FpCategories/.gitignore new file mode 100644 index 0000000..7c0ec6a --- /dev/null +++ b/FpCategories/.gitignore @@ -0,0 +1 @@ +.generate.sh diff --git a/FpCategories/LICENSE b/FpCategories/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/FpCategories/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/FpCategories/Project.toml b/FpCategories/Project.toml new file mode 100644 index 0000000..750ae44 --- /dev/null +++ b/FpCategories/Project.toml @@ -0,0 +1,35 @@ +name = "FpCategories" +uuid = "b9f20f1b-1226-4811-b6a0-b2e47a225553" +authors = [ + "Mohamed Barakat ", + "Kamal Saleh " +] + +# Transpiled from GAP's FpCategories v2025.11-05 +version = "0.0.1" + +[deps] +CAP = "d64df2ee-d2bb-46f4-8cbc-f03bb858f8cb" +CartesianCategories = "c5961c08-7b59-43f4-a15e-02b3e7c87ab8" +ToolsForCategoricalTowers = "e2cf920d-0824-4cbb-97bb-0be40824f89f" +QuotientCategories = "c103c924-3523-4680-a691-c88f3312ec70" +FinSetsForCAP = "0a079e9b-4bc2-44fe-a89b-7607e4464786" + +[weakdeps] + +[extensions] + +[compat] +julia = "1.11" +CAP = "0.6" +CartesianCategories = "~0.3.12" +ToolsForCategoricalTowers = "~0.0.1" +QuotientCategories = "~0.0.2" +FinSetsForCAP = "~0.1.15" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" + +[targets] +test = ["Test", "Documenter"] diff --git a/FpCategories/README.md b/FpCategories/README.md new file mode 100644 index 0000000..b9d1ac8 --- /dev/null +++ b/FpCategories/README.md @@ -0,0 +1,23 @@ + +# FpCategories + +### Finitely presented categories by generating quivers and relations + +| Documentation | +| ------------- | +| [![HTML stable documentation][html-img]][html-url] [![PDF stable documentation][pdf-img]][pdf-url] | + + + +This is the Julia version of the [CAP-based][CAP_based] package [FpCategories][FpCategories]. + +[CAP_based]: https://homalg-project.github.io/docs/CAP_project-based/ +[FpCategories]: https://homalg-project.github.io/pkg/FpCategories + + +[html-img]: https://img.shields.io/badge/πŸ”—%20HTML-stable-blue.svg +[html-url]: https://homalg-project.github.io/CategoricalTowers/FpCategories/doc/chap0_mj.html + +[pdf-img]: https://img.shields.io/badge/πŸ”—%20PDF-stable-blue.svg +[pdf-url]: https://homalg-project.github.io/CategoricalTowers/FpCategories/download_pdf.html + diff --git a/FpCategories/docs/src/AutoDocTests.tst.autogen.md b/FpCategories/docs/src/AutoDocTests.tst.autogen.md new file mode 100644 index 0000000..6b8a0a8 --- /dev/null +++ b/FpCategories/docs/src/AutoDocTests.tst.autogen.md @@ -0,0 +1,589 @@ + +```jldoctest AutoDocTests +julia> using CAP, QuotientCategories, FpCategories + +julia> true +true + +julia> str = "q(0..5)[x:0->0,s:0->1,a:1->2,c:1->3,e:1->4,b:2->4,d:3->4,t:4->5,y:5->5]"; + +julia> q = FinQuiver( str ) +FinQuiver( "q(0,1,2,3,4,5)[x:0β†’0,s:0β†’1,a:1β†’2,c:1β†’3,e:1β†’4,b:2β†’4,d:3β†’4, +t:4β†’5,y:5β†’5]" ) + +julia> QuiverName( q ) +"q" + +julia> NumberOfObjects( q ) +6 + +julia> Display( LabelsOfObjects( q ) ) +[ "0", "1", "2", "3", "4", "5" ] + +julia> Display( SetOfObjects( q ) ) +[ (0), (1), (2), (3), (4), (5) ] + +julia> o = q["0"] +(0) + +julia> ObjectIndex( o ) +1 + +julia> IsIdenticalObj( o, ObjectConstructor( q, 1 ) ) +true + +julia> ObjectLabel( o ) +"0" + +julia> LaTeXOutput( o ) +"0" + +julia> NumberOfMorphisms( q ) +9 + +julia> Display( LabelsOfMorphisms( q ) ) +[ "x", "s", "a", "c", "e", "b", "d", "t", "y" ] + +julia> Display( IndicesOfSources( q ) ) +[ 1, 1, 2, 2, 2, 3, 4, 5, 6 ] + +julia> Display( IndicesOfTargets( q ) ) +[ 1, 2, 3, 4, 5, 5, 5, 6, 6 ] + +julia> Display( SetOfMorphisms( q ) ) +[ x:(0) β†’ (0), s:(0) β†’ (1), a:(1) β†’ (2), c:(1) β†’ (3), e:(1) β†’ (4), + b:(2) β†’ (4), d:(3) β†’ (4), t:(4) β†’ (5), y:(5) β†’ (5) ] + +julia> m = q.y +y:(5) β†’ (5) + +julia> MorphismIndex( m ) +9 + +julia> IsIdenticalObj( m, MorphismConstructor( q, q["5"], 9, q["5"] ) ) +true + +julia> MorphismLabel( m ) +"y" + +julia> Display( MorphismsOfExternalHom( q["0"], q["0"] ) ) +[ x:(0) β†’ (0) ] + +julia> Display( MorphismsOfExternalHom( q["0"], q["1"] ) ) +[ s:(0) β†’ (1) ] + +julia> q_op = OppositeQuiver( q ) +FinQuiver( "q_op(0,1,2,3,4,5)[x:0β†’0,s:1β†’0,a:2β†’1,c:3β†’1,e:4β†’1,b:4β†’2, +d:4β†’3,t:5β†’4,y:5β†’5]" ) + +julia> Display( MorphismsOfExternalHom( q_op["1"], q_op["0"] ) ) +[ s:(1) β†’ (0) ] + +julia> q_op_x_q = TensorProductOfFinQuivers( q_op, q ); + +julia> NumberOfObjects( q_op_x_q ) +36 + +julia> NumberOfMorphisms( q_op_x_q ) +108 + +``` + +```jldoctest AutoDocTests +julia> using CAP, QuotientCategories, FpCategories + +julia> q1 = RandomFinQuiver( 2, 4, false ); + +julia> q2 = RandomFinQuiver( 2, 4, true ); + +julia> @Assert( 0, NumberOfObjects( q1 ) == 2 ) + +julia> @Assert( 0, NumberOfMorphisms( q1 ) == 4 ) + +julia> @Assert( 0, Length( Filtered( SetOfMorphisms( q1 ), IsEndomorphism ) ) == 0 ) + +julia> @Assert( 0, Length( Filtered( SetOfMorphisms( q2 ), IsEndomorphism ) ) > 0 ) + +julia> q3 = FinQuiver( "q(3)[a:1->2,b:2->3]" ) +FinQuiver( "q(1,2,3)[a:1β†’2,b:2β†’3]" ) + +julia> q4 = FinQuiver( "q(4..6)[a:4->5,b:5->6]" ) +FinQuiver( "q(4,5,6)[a:4β†’5,b:5β†’6]" ) + +``` + +```jldoctest AutoDocTests +julia> using CAP, QuotientCategories, FpCategories + +julia> true +true + +julia> Delta2 = SimplicialCategoryTruncatedInDegree( 2 ) +PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1,ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == id(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] + +julia> Perform( DefiningRelations( Delta2 ), Display ) +[ sβ‹…id:(C0) β†’ (C0), id(C0):(C0) β†’ (C0) ] +[ tβ‹…id:(C0) β†’ (C0), id(C0):(C0) β†’ (C0) ] +[ psβ‹…is:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ ptβ‹…it:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ isβ‹…id:(C2) β†’ (C0), itβ‹…id:(C2) β†’ (C0) ] +[ ptβ‹…is:(C1) β†’ (C1), idβ‹…t:(C1) β†’ (C1) ] +[ psβ‹…it:(C1) β†’ (C1), idβ‹…s:(C1) β†’ (C1) ] +[ sβ‹…pt:(C0) β†’ (C2), tβ‹…ps:(C0) β†’ (C2) ] +[ sβ‹…mu:(C0) β†’ (C2), sβ‹…ps:(C0) β†’ (C2) ] +[ tβ‹…mu:(C0) β†’ (C2), tβ‹…pt:(C0) β†’ (C2) ] +[ muβ‹…is:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ muβ‹…it:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] + +julia> Size( Delta2 ) +31 + +julia> N = NerveTruncatedInDegree2AsFunctor( Delta2 ) +Functor from PathCategory( FinQuiver( + "Delta_op(C0,C1,C2)[id:C0β†’C1,s:C1β†’C0,t:C1β†’C0, + is:C1β†’C2,it:C1β†’C2,ps:C2β†’C1,pt:C2β†’C1,mu:C2β†’C1]" ) ) +/ [ idβ‹…s == id(C0), idβ‹…t == id(C0), isβ‹…ps == id(C1), ... ] -> SkeletalFinSets + +julia> Delta2op = SourceOfFunctor( N ) +PathCategory( FinQuiver( + "Delta_op(C0,C1,C2)[id:C0β†’C1,s:C1β†’C0,t:C1β†’C0, + is:C1β†’C2,it:C1β†’C2,ps:C2β†’C1,pt:C2β†’C1,mu:C2β†’C1]" ) ) +/ [ idβ‹…s == id(C0), idβ‹…t == id(C0), isβ‹…ps == id(C1), ... ] + +julia> ApplyFunctor( N, Delta2op.C0 ) +|3| + +julia> Display( ApplyFunctor( N, Delta2op.C0 ) ) +[ 0, 1, 2 ] + +julia> ApplyFunctor( N, Delta2op.C1 ) +|31| + +julia> Display( ApplyFunctor( N, Delta2op.C1 ) ) +[ 0,..., 30 ] + +julia> ApplyFunctor( N, Delta2op.C2 ) +|393| + +julia> Display( ApplyFunctor( N, Delta2op.C2 ) ) +[ 0,..., 392 ] + +julia> ApplyFunctor( N, Delta2op.id ) +|3| β†’ |31| + +julia> Display( ApplyFunctor( N, Delta2op.id ) ) +[ 0, 1, 2 ] β±Ά[ 0, 5, 21 ]β†’ [ 0,..., 30 ] + +``` + +```jldoctest AutoDocTests +julia> using CAP, QuotientCategories, FpCategories + +julia> Delta2 = SimplicialCategoryTruncatedInDegree( 2 ) +PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == id(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] + +julia> Perform( DefiningRelations( Delta2 ), Display ) +[ sβ‹…id:(C0) β†’ (C0), id(C0):(C0) β†’ (C0) ] +[ tβ‹…id:(C0) β†’ (C0), id(C0):(C0) β†’ (C0) ] +[ psβ‹…is:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ ptβ‹…it:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ isβ‹…id:(C2) β†’ (C0), itβ‹…id:(C2) β†’ (C0) ] +[ ptβ‹…is:(C1) β†’ (C1), idβ‹…t:(C1) β†’ (C1) ] +[ psβ‹…it:(C1) β†’ (C1), idβ‹…s:(C1) β†’ (C1) ] +[ sβ‹…pt:(C0) β†’ (C2), tβ‹…ps:(C0) β†’ (C2) ] +[ sβ‹…mu:(C0) β†’ (C2), sβ‹…ps:(C0) β†’ (C2) ] +[ tβ‹…mu:(C0) β†’ (C2), tβ‹…pt:(C0) β†’ (C2) ] +[ muβ‹…is:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ muβ‹…it:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] + +julia> Size( Delta2 ) +31 + +julia> Ymu = YonedaCompositionAsNaturalEpimorphism( Delta2 ) +Natural transformation from +Functor from PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == i d(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] -> SkeletalFinSets +-> +Functor from PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == i d(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] -> SkeletalFinSets + +julia> Ymu = YonedaProjectionAsNaturalEpimorphism( Delta2 ) +Natural transformation from +Functor from PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == i d(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] -> SkeletalFinSets +-> +Functor from PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == i d(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] -> SkeletalFinSets + +julia> Ys = YonedaFibrationAsNaturalTransformation( Delta2 ) +Natural transformation from +Functor from PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == i d(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] -> SkeletalFinSets +-> +Functor from PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == i d(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] -> SkeletalFinSets + +``` + +```jldoctest AutoDocTests +julia> using CAP, QuotientCategories, FpCategories + +julia> true +true + +julia> Delta1 = SimplicialCategoryTruncatedInDegree( 1 ) +PathCategory( FinQuiver( "Delta(C0,C1)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1]" ) ) +/ [ sβ‹…id == id(C0), tβ‹…id == id(C0) ] + +julia> Size( Delta1 ) +7 + +julia> C = CategoryFromNerveData( Delta1 ) +PathCategory( FinQuiver( "Delta(C0,C1)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1]" ) ) +/ [ sβ‹…id == id(C0), tβ‹…id == id(C0) ] + +julia> Size( C ) +7 + +julia> NerveTruncatedInDegree2Data( C ) == NerveTruncatedInDegree2Data( Delta1 ) +true + +julia> Display( IndicesOfGeneratingMorphisms( C ) ) +[ 1, 2, 3 ] + +julia> Perform( SetOfGeneratingMorphisms( C ), Display ) +(C1)-[(id)]β†’(C0) +(C0)-[(s)]β†’(C1) +(C0)-[(t)]β†’(C1) + +julia> Display( C ) +A CAP category with name +PathCategory( FinQuiver( "Delta(C0,C1)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1]" ) ) +/ [ sβ‹…id == id(C0), tβ‹…id == id(C0) ]: + +19 primitive operations were used to derive 55 operations for this category +which algorithmically +* IsCategoryWithDecidableColifts +* IsCategoryWithDecidableLifts +* IsFiniteCategory +* IsEquippedWithHomomorphismStructure + +julia> C0 = CreateObject( C, 0 ) +<(C0)> + +julia> IsWellDefined( C0 ) +true + +julia> C1 = 1 / C +<(C1)> + +julia> IsWellDefined( C1 ) +true + +julia> IsWellDefined( 2 / C ) +false + +julia> idC0 = CreateMorphism( C0, 0, C0 ) +(C0)-[(C0)]β†’(C0) + +julia> CreateMorphism( C, 0 ) == idC0 +true + +julia> IsOne( idC0 ) +true + +julia> id = CreateMorphism( C, 1 ) +(C1)-[(id)]β†’(C0) + +julia> s = CreateMorphism( C, 2 ) +(C0)-[(s)]β†’(C1) + +julia> t = CreateMorphism( C, 3 ) +(C0)-[(t)]β†’(C1) + +julia> idC1 = CreateMorphism( C, 4 ) +(C1)-[(C1)]β†’(C1) + +julia> IsOne( idC1 ) +true + +julia> sigma = CreateMorphism( C, 5 ) +(C1)-[(idβ‹…s)]β†’(C1) + +julia> IsEndomorphism( sigma ) +true + +julia> IsOne( sigma ) +false + +julia> tau = CreateMorphism( C, 6 ) +(C1)-[(idβ‹…t)]β†’(C1) + +julia> IsEndomorphism( tau ) +true + +julia> IsOne( tau ) +false + +julia> IsWellDefined( CreateMorphism( C1, 7, C1 ) ) +false + +julia> PreCompose( s, id ) == idC0 +true + +julia> PreCompose( t, id ) == idC0 +true + +julia> PreCompose( id, s ) == sigma +true + +julia> PreCompose( id, t ) == tau +true + +julia> HomStructure( C0, C0 ) +|1| + +julia> HomStructure( C1, C1 ) +|3| + +julia> HomStructure( C0, C1 ) +|2| + +julia> HomStructure( C1, C0 ) +|1| + +julia> Display( HomStructure( s ) ) +[ 0 ] β±Ά[ 0 ]β†’ [ 0, 1 ] + +julia> Display( HomStructure( t ) ) +[ 0 ] β±Ά[ 1 ]β†’ [ 0, 1 ] + +julia> HomStructure( Source( s ), Target( s ), HomStructure( s ) ) == s +true + +julia> HomStructure( Source( t ), Target( t ), HomStructure( t ) ) == t +true + +julia> Display( HomStructure( s, t ) ) +[ 0 ] β±Ά[ 1 ]β†’ [ 0, 1 ] + +julia> Display( HomStructure( t, s ) ) +[ 0 ] β±Ά[ 0 ]β†’ [ 0, 1 ] + +julia> Display( HomStructure( sigma, tau ) ) +[ 0, 1, 2 ] β±Ά[ 2, 2, 2 ]β†’ [ 0, 1, 2 ] + +julia> Display( HomStructure( + PreCompose( Delta1.id, Delta1.s ), + PreCompose( Delta1.id, Delta1.t ) ) ) +[ 0, 1, 2 ] β±Ά[ 2, 2, 2 ]β†’ [ 0, 1, 2 ] + +julia> Display( HomStructure( tau, sigma ) ) +[ 0, 1, 2 ] β±Ά[ 1, 1, 1 ]β†’ [ 0, 1, 2 ] + +julia> Display( HomStructure( + PreCompose( Delta1.id, Delta1.t ), + PreCompose( Delta1.id, Delta1.s ) ) ) +[ 0, 1, 2 ] β±Ά[ 1, 1, 1 ]β†’ [ 0, 1, 2 ] + +julia> Display( HomStructure( tau, idC1 ) ) +[ 0, 1, 2 ] β±Ά[ 2, 1, 2 ]β†’ [ 0, 1, 2 ] + +julia> Display( HomStructure( idC1, idC1 ) ) +[ 0, 1, 2 ] β±Ά[ 0, 1, 2 ]β†’ [ 0, 1, 2 ] + +julia> C_op = OppositeCategoryFromNerveData( C ) +Opposite( +PathCategory( FinQuiver( "Delta(C0,C1)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1]" ) ) +/ [ sβ‹…id == id(C0), tβ‹…id == id(C0) ] ) + +julia> NerveData( C_op ) == NerveTruncatedInDegree2Data( C_op ) +true + +julia> IsIdenticalObj( OppositeCategoryFromNerveData( C_op ), C ) +true + +julia> Display( IndicesOfGeneratingMorphisms( C_op ) ) +[ 3, 1, 2 ] + +julia> Perform( SetOfGeneratingMorphisms( C_op ), Display ) +(C0)-[(id)]β†’(C1) +(C1)-[(s)]β†’(C0) +(C1)-[(t)]β†’(C0) + +``` + +```jldoctest AutoDocTests +julia> using CAP, QuotientCategories, FpCategories + +julia> true +true + +julia> str = "q(0..5)[x:0->0,s:0->1,a:1->2,c:1->3,e:1->4,b:2->4,d:3->4,t:4->5,y:5->5]"; + +julia> q = FinQuiver( str ) +FinQuiver( "q(0,1,2,3,4,5)[x:0β†’0,s:0β†’1,a:1β†’2,c:1β†’3,e:1β†’4,b:2β†’4,d:3β†’4, +t:4β†’5,y:5β†’5]" ) + +julia> C = PathCategory( q; admissible_order = "Dp" ) +PathCategory( FinQuiver( "q(0,1,2,3,4,5)[x:0β†’0,s:0β†’1,a:1β†’2,c:1β†’3,e:1β†’4, +b:2β†’4,d:3β†’4,t:4β†’5,y:5β†’5]" ) ) + +julia> Display( C ) +A CAP category with name PathCategory( FinQuiver( "q(0,1,2,3,4,5)[x:0β†’0,s:0β†’1, +a:1β†’2,c:1β†’3,e:1β†’4,b:2β†’4,d:3β†’4,t:4β†’5,y:5β†’5]" ) ): + +17 primitive operations were used to derive 32 operations for this category +which algorithmically +* IsFinitelyPresentedCategory + +julia> Display( SetOfObjects( C ) ) +[ (0), (1), (2), (3), (4), (5) ] + +julia> Display( SetOfGeneratingMorphisms( C ) ) +[ x:(0) β†’ (0), s:(0) β†’ (1), a:(1) β†’ (2), c:(1) β†’ (3), e:(1) β†’ (4), + b:(2) β†’ (4), d:(3) β†’ (4), t:(4) β†’ (5), y:(5) β†’ (5) ] + +julia> C["5"] +(5) + +julia> ObjectIndex( C["5"] ) +6 + +julia> C.id_5 == "id(5)" / C +true + +julia> m = C["x^2*s*a*b*t*y^2"] +x^2β‹…sβ‹…aβ‹…bβ‹…tβ‹…y^2:(0) β†’ (5) + +julia> m = C["x^2sabty^2"] +x^2β‹…sβ‹…aβ‹…bβ‹…tβ‹…y^2:(0) β†’ (5) + +julia> IsWellDefined( m ) +true + +julia> MorphismLength( m ) +8 + +julia> Display( MorphismIndices( m ) ) +[ 1, 1, 2, 3, 6, 8, 9, 9 ] + +julia> Perform( MorphismSupport( m ), Display ) +x:(0) β†’ (0) +x:(0) β†’ (0) +s:(0) β†’ (1) +a:(1) β†’ (2) +b:(2) β†’ (4) +t:(4) β†’ (5) +y:(5) β†’ (5) +y:(5) β†’ (5) + +julia> m == MorphismConstructor( C, Source( m ), [ MorphismLength( m ), MorphismIndices( m ) ], Target( m ) ) +true + +julia> relations = [ [ C.x^5, C.x ], [ C.y^5, C.y^2 ] ]; + +julia> qC = QuotientCategory( C, relations ) +PathCategory( FinQuiver( "q(0,1,2,3,4,5)[x:0β†’0,s:0β†’1,a:1β†’2,c:1β†’3,e:1β†’4, +b:2β†’4,d:3β†’4,t:4β†’5,y:5β†’5]" ) ) / [ x^5 == x, y^5 == y^2 ] + +julia> Display( qC ) +A CAP category with name PathCategory( FinQuiver( "q(0,1,2,3,4,5)[x:0β†’0,s:0β†’1, +a:1β†’2,c:1β†’3,e:1β†’4,b:2β†’4,d:3β†’4,t:4β†’5,y:5β†’5]" ) ) / [ x^5 == x, y^5 == y^2 ]: + +24 primitive operations were used to derive 65 operations for this category +which algorithmically +* IsCategoryWithDecidableColifts +* IsCategoryWithDecidableLifts +* IsFiniteCategory +* IsEquippedWithHomomorphismStructure + +julia> "0" / qC +(0) + +julia> ObjectIndex( qC["0"] ) +1 + +julia> qC.x^7 +[x^3]:(0) β†’ (0) + +julia> CanonicalRepresentative( qC.x^7 ) +x^3:(0) β†’ (0) + +julia> HomomorphismStructureOnObjects( qC["0"], qC["5"] ) +|75| + +julia> Display( List( SetOfGeneratingMorphisms( qC ), IsMonomorphism ) ) +[ false, true, true, true, true, true, true, true, false ] + +julia> Display( List( SetOfGeneratingMorphisms( qC ), IsEpimorphism ) ) +[ false, true, true, true, true, true, true, true, false ] + +``` + +```jldoctest AutoDocTests +julia> using CAP, QuotientCategories, FpCategories + +julia> true +true + +julia> Delta2 = SimplicialCategoryTruncatedInDegree( 2 ) +PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) +/ [ sβ‹…id == id(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] + +julia> Perform( DefiningRelations( Delta2 ), Display ) +[ sβ‹…id:(C0) β†’ (C0), id(C0):(C0) β†’ (C0) ] +[ tβ‹…id:(C0) β†’ (C0), id(C0):(C0) β†’ (C0) ] +[ psβ‹…is:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ ptβ‹…it:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ isβ‹…id:(C2) β†’ (C0), itβ‹…id:(C2) β†’ (C0) ] +[ ptβ‹…is:(C1) β†’ (C1), idβ‹…t:(C1) β†’ (C1) ] +[ psβ‹…it:(C1) β†’ (C1), idβ‹…s:(C1) β†’ (C1) ] +[ sβ‹…pt:(C0) β†’ (C2), tβ‹…ps:(C0) β†’ (C2) ] +[ sβ‹…mu:(C0) β†’ (C2), sβ‹…ps:(C0) β†’ (C2) ] +[ tβ‹…mu:(C0) β†’ (C2), tβ‹…pt:(C0) β†’ (C2) ] +[ muβ‹…is:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] +[ muβ‹…it:(C1) β†’ (C1), id(C1):(C1) β†’ (C1) ] + +julia> Size( Delta2 ) +31 + +julia> Delta2_op = OppositeFiniteCategory( Delta2 ) +Opposite( PathCategory( FinQuiver( + "Delta(C0,C1,C2)[id:C1β†’C0,s:C0β†’C1,t:C0β†’C1, + is:C2β†’C1,it:C2β†’C1, + ps:C1β†’C2,pt:C1β†’C2,mu:C1β†’C2]" ) ) / +[ sβ‹…id == id(C0), tβ‹…id == id(C0), psβ‹…is == id(C1), ... ] ) + +julia> IsIdenticalObj( OppositeFiniteCategory( Delta2_op ), Delta2 ) +true + +``` diff --git a/FpCategories/docs/src/HasFiniteNumberOfMacaulayMonomials.tst.autogen.md b/FpCategories/docs/src/HasFiniteNumberOfMacaulayMonomials.tst.autogen.md new file mode 100644 index 0000000..facec2b --- /dev/null +++ b/FpCategories/docs/src/HasFiniteNumberOfMacaulayMonomials.tst.autogen.md @@ -0,0 +1,24 @@ + +julia> true +true + +```jldoctest +julia> using CAP, QuotientCategories, FpCategories + +julia> C = PathCategory( FinQuiver( "q(1,2,3,4,5,6,7)[12:1->2,23:2->3,34:3->4,45:4->5,56:5->6,67:6->7,77:7->7,71:7->1]" ) ); + +julia> @Assert( 0, @not HasFiniteNumberOfMacaulayMorphisms( C, [ C["12*23*34*45*56*67*77*71"] ] ) ) + +julia> @Assert( 0, @not HasFiniteNumberOfMacaulayMorphisms( C, [ C["77"], C["12*23*34*45*56*67*77*71"] ] ) ) + +julia> @Assert( 0, @not HasFiniteNumberOfMacaulayMorphisms( C, [ C["12*23*34*45*56*67*71"], C["12*23*34*45*56*67*77*71"] ] ) ) + +julia> @Assert( 0, HasFiniteNumberOfMacaulayMorphisms( C, [ C["77"], C["12*23*34*45*56*67*71"] ] ) ) + +julia> @Assert( 0, HasFiniteNumberOfMacaulayMorphisms( C, [ C["77"], C["id_1"] ] ) ) + +julia> @Assert( 0, @not HasFiniteNumberOfMacaulayMorphisms( C, [ C["id_1"] ] ) ) + +julia> @Assert( 0, HasFiniteNumberOfMacaulayMorphisms( C, [ C["id_7"] ] ) ) + +``` diff --git a/FpCategories/makefile b/FpCategories/makefile new file mode 100644 index 0000000..50b0dee --- /dev/null +++ b/FpCategories/makefile @@ -0,0 +1,44 @@ +.PHONY: test + +install: + julia -e 'using Pkg; Pkg.develop(path=".");' + +uninstall: + julia -e 'using Pkg; Pkg.rm("FpCategories");' + +test: + julia -e 'using Pkg; Pkg.test("FpCategories");' + +gen: + rm -f ./src/gap/*.autogen.jl + rm -f ./src/gap/*/*.autogen.jl + rm -f ./docs/src/*.autogen.md + ./.generate.sh -e gen_full=0 + +gen-full: + rm -f ./src/gap/*.autogen.jl + rm -f ./src/gap/*/*.autogen.jl + rm -f ./docs/src/*.autogen.md + ./.generate.sh -e gen_full=1 + +git-commit: + @if [ -n "$$(git diff .)" ]; then \ + echo "Committing changes ..."; \ + git add .; \ + git commit \ + -m "Update to GAP's $$(grep "# Transpiled from GAP's" "Project.toml" | cut -d ' ' -f 5-)" \ + -m "Bump Version to v$$(grep "version = " "Project.toml" | cut -d '"' -f 2)" \ + ; \ + else \ + echo "No changes to commit."; \ + fi + +codecov: + julia --project=. -e 'using Coverage; using Pkg; Pkg.test(coverage=true); LCOV.writefile("coverage.lcov", process_folder(pwd()));' + genhtml -o coverage_report coverage.lcov + open coverage_report/index.html + +clean-codecov: + find . -type f -name "*.jl.*.cov" -exec rm -f {} + + rm -f coverage.lcov + rm -rf coverage_report diff --git a/FpCategories/src/FpCategories.jl b/FpCategories/src/FpCategories.jl new file mode 100644 index 0000000..2664184 --- /dev/null +++ b/FpCategories/src/FpCategories.jl @@ -0,0 +1,19 @@ +module FpCategories + +@nospecialize + +using CAP + +using CartesianCategories + +using ToolsForCategoricalTowers + +using QuotientCategories + +using FinSetsForCAP + +include("init.jl") + +include("post_init.jl") + +end # module FpCategories diff --git a/FpCategories/src/gap/CategoryFromNerveData.gd.autogen.jl b/FpCategories/src/gap/CategoryFromNerveData.gd.autogen.jl new file mode 100644 index 0000000..74d40c8 --- /dev/null +++ b/FpCategories/src/gap/CategoryFromNerveData.gd.autogen.jl @@ -0,0 +1,205 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# FpCategories: Finitely presented categories by generating quivers and relations +# +# Declarations +# + +#! @Chapter Finite categories from nerve data + +#################################### +# +#! @Section GAP categories +# +#################################### + +#! @Description +#! The &GAP; category of categories from nerve data. +@DeclareFilter( "IsCategoryFromNerveData", + IsCapCategory ); + +#! @Description +#! The &GAP; category of objects in a category from nerve data. +@DeclareFilter( "IsObjectInCategoryFromNerveData", IsCapCategoryObject ); + +#! @Description +#! The &GAP; category of morphisms in a category from nerve data. +@DeclareFilter( "IsMorphismInCategoryFromNerveData", IsCapCategoryMorphism ); + +#################################### +# +#! @Section Attributes +# +#################################### + +#! @Description +#! The nerve data used to create the category C. +#! It might differ from the normalized output of +#! NerveTruncatedInDegree2Data( C ). +#! @Arguments C +#! @Returns a pair consisting of a triple and an 8-tuple +@DeclareAttribute( "NerveData", + IsCategoryFromNerveData ); + +CapJitAddTypeSignature( "NerveData", [ IsCapCategory ], + function ( input_types ) + local V, obj, mor; + + @Assert( 0, HasIsFiniteCategory( input_types[1].category ) && IsFiniteCategory( input_types[1].category ) ); + + V = RangeCategoryOfHomomorphismStructure( input_types[1].category ); + + obj = CapJitDataTypeOfObjectOfCategory( V ); + mor = CapJitDataTypeOfMorphismOfCategory( V ); + + return CapJitDataTypeOfNTupleOf( 2, + CapJitDataTypeOfNTupleOf( 3, + obj, # Cβ‚€ + obj, # C₁ + obj ), # Cβ‚‚ + CapJitDataTypeOfNTupleOf( 8, + mor, # id: Cβ‚€ β†’ C₁ + mor, # s: C₁ β†’ Cβ‚€ + mor, # t: C₁ β†’ Cβ‚€ + mor, # ΞΉβ‚›: C₁ β†’ Cβ‚‚ + mor, # ΞΉβ‚œ: C₁ β†’ Cβ‚‚ + mor, # pβ‚›: Cβ‚‚ β†’ C₁ + mor, # pβ‚œ: Cβ‚‚ β†’ C₁ + mor ) ); # ΞΌ: Cβ‚‚ β†’ C₁ + +end ); + +@DeclareAttribute( "IndicesOfGeneratingMorphisms", + IsCategoryFromNerveData ); + +CapJitAddTypeSignature( "IndicesOfGeneratingMorphisms", [ IsCategoryFromNerveData ], + function ( input_types ) + + return CapJitDataTypeOfListOf( IsBigInt ); + +end ); + +@DeclareAttribute( "DecompositionIndicesOfAllMorphisms", + IsCategoryFromNerveData ); + +#CapJitAddTypeSignature( "DecompositionIndicesOfAllMorphisms", [ IsCategoryFromNerveData ], +# function ( input_types ) +# +# return CapJitDataTypeOfListOf( +# CapJitDataTypeOfListOf( IsInt ) ); +# +#end ); + +@DeclareAttribute( "RelationsAmongGeneratingMorphisms", + IsCategoryFromNerveData ); + +#CapJitAddTypeSignature( "RelationsAmongGeneratingMorphisms", [ IsCategoryFromNerveData ], +# function ( input_types ) +# +# return CapJitDataTypeOfListOf( +# CapJitDataTypeOfNTupleOf( 2, +# CapJitDataTypeOfListOf( IsInt ), +# CapJitDataTypeOfListOf( IsInt ) ) ); +# +#end ); + +#! @Description +#! The number of morphisms in the category C created from nerve data. +#! @Arguments C +#! @Returns a nonnegative integer +@DeclareAttribute( "Size", + IsCategoryFromNerveData ); + +## +@DeclareAttribute( "MapOfObject", + IsObjectInCategoryFromNerveData ); + +CapJitAddTypeSignature( "MapOfObject", [ IsObjectInCategoryFromNerveData ], + function ( input_types ) + local V; + + @Assert( 0, IsCategoryFromNerveData( input_types[1].category ) ); + + V = RangeCategoryOfHomomorphismStructure( input_types[1].category ); + + return CapJitDataTypeOfMorphismOfCategory( V ); + +end ); + +## +@DeclareAttribute( "MapOfMorphism", + IsMorphismInCategoryFromNerveData ); + +CapJitAddTypeSignature( "MapOfMorphism", [ IsMorphismInCategoryFromNerveData ], + function ( input_types ) + local V; + + @Assert( 0, IsCategoryFromNerveData( input_types[1].category ) ); + + V = RangeCategoryOfHomomorphismStructure( input_types[1].category ); + + return CapJitDataTypeOfMorphismOfCategory( V ); + +end ); + +## +@DeclareAttribute( "OppositeNerveData", + IsList ); + +#! @Description +#! The opposite category of the category C defined by nerve data. +#! @Arguments C +#! @Returns a &CAP; category +@DeclareAttribute( "OppositeCategoryFromNerveData", + IsCategoryFromNerveData ); + +@DeclareAttribute( "DecompositionIndicesOfAllMorphismsFromHomStructure", + IsCapCategory ); + +#################################### +# +#! @Section Constructors +# +#################################### + +#! @Description +#! Construct an enriched finite category out of the input_record +#! consisting of values to the keys: +#! * name +#! * range_of_HomStructure +#! * data_tables +#! * indices_of_generating_morphisms +#! * relations +#! * labels +#! * properties +#! @Arguments input_record +#! @Returns a &CAP; category +@DeclareAttribute( "CategoryFromNerveData", + IsRecord ); +#! @InsertChunk CategoryFromNerveData + +if (false) +#! @Arguments C +@DeclareAttribute( "CategoryFromNerveData", + IsCategoryFromDataTables ); +end; + +#! @Description +#! Construct the o-th object in the category C created from nerve data. +#! @Arguments C, o +#! @Returns a &CAP; category +@DeclareOperation( "CreateObject", + [ IsCategoryFromNerveData, IsBigInt ] ); + +#! @Description +#! Construct the m-th morphism source$\to$range +#! in the category C created from nerve data. +#! @Arguments C, m +#! @Returns a &CAP; category +#! @Group CreateMorphism +@DeclareOperation( "CreateMorphism", + [ IsCategoryFromNerveData, IsBigInt ] ); + +#! @Arguments source, m, range +#! @Group CreateMorphism +@DeclareOperation( "CreateMorphism", + [ IsObjectInCategoryFromNerveData, IsBigInt, IsObjectInCategoryFromNerveData ] ); diff --git a/FpCategories/src/gap/CategoryFromNerveData.gi.autogen.jl b/FpCategories/src/gap/CategoryFromNerveData.gi.autogen.jl new file mode 100644 index 0000000..dc55912 --- /dev/null +++ b/FpCategories/src/gap/CategoryFromNerveData.gi.autogen.jl @@ -0,0 +1,1086 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# FpCategories: Finitely presented categories by generating quivers and relations +# +# Implementations +# + +## +@InstallMethod( CategoryFromNerveData, + "for a record", + [ IsRecord ], + + function( input_record ) + local known_keys_with_filters, key, filter, nerve_data, C0, C, prop, V, s, t; + + ## check the keys of the given input record + known_keys_with_filters = + @rec( name = IsString, + nerve_data = IsList, + indices_of_generating_morphisms = IsList, + decomposition_of_all_morphisms = IsList, + relations = IsList, + labels = IsList, + properties = IsList ); + + for key in RecNames( input_record ) + + if (@IsBound( known_keys_with_filters[key] )) + + filter = known_keys_with_filters[key]; + + if (@not filter( input_record[key] )) + + # COVERAGE_IGNORE_NEXT_LINE + Error( "The value of the key `", key, "` must lie in the filter ", filter ); + + end; + + else + + # COVERAGE_IGNORE_NEXT_LINE + Error( "The following record key is not known to `CategoryFromNerveData`: ", key ); + + end; + + end; + + nerve_data = input_record.nerve_data; + + C0 = nerve_data[1][1]; + + V = CapCategory( C0 ); + + C = CreateCapCategoryWithDataTypes( input_record.name, + IsCategoryFromNerveData, + IsObjectInCategoryFromNerveData, + IsMorphismInCategoryFromNerveData, + IsCapCategoryTwoCell, + CapJitDataTypeOfMorphismOfCategory( V ), + CapJitDataTypeOfMorphismOfCategory( V ), + fail ); + + SetIsFiniteCategory( C, true ); + + for prop in input_record.properties + + Setter( ValueGlobal( prop ) )( C, true ); + + end; + + SetIndicesOfGeneratingMorphisms( C, input_record.indices_of_generating_morphisms ); + SetDecompositionIndicesOfAllMorphisms( C, input_record.decomposition_of_all_morphisms ); + SetRelationsAmongGeneratingMorphisms( C, input_record.relations ); + + C.labels = input_record.labels; + + SET_RANGE_CATEGORY_Of_HOMOMORPHISM_STRUCTURE( C, V ); + + SetNerveData( C, nerve_data ); + + ## s: C₁ β†’ Cβ‚€ + s = nerve_data[2][2]; + + ## t: C₁ β†’ Cβ‚€ + t = nerve_data[2][3]; + + SetDefiningTripleOfUnderlyingQuiver( C, + Triple( Length( C0 ), + Length( input_record.indices_of_generating_morphisms ), + List( input_record.indices_of_generating_morphisms, i -> PairGAP( s( i ), t( i ) ) ) ) ); + + C.compiler_hints = + @rec( category_attribute_names = + [ "NerveData", + "IndicesOfGeneratingMorphisms", + "DecompositionIndicesOfAllMorphisms", + "RelationsAmongGeneratingMorphisms", + "DefiningTripleOfUnderlyingQuiver", + ] ); + + ## + AddObjectConstructor( C, + function( C, obj_map ) + + return CreateCapCategoryObjectWithAttributes( C, + MapOfObject, obj_map ); + + end ); + + ## + AddObjectDatum( C, + function( C, obj ) + + return MapOfObject( obj ); + + end ); + + ## + AddMorphismConstructor( C, + function( C, source, mor_map, range ) + + return CreateCapCategoryMorphismWithAttributes( C, + source, + range, + MapOfMorphism, mor_map ); + + end ); + + ## + AddMorphismDatum( C, + function( C, mor ) + + return MapOfMorphism( mor ); + + end ); + + ## + AddSetOfObjectsOfCategory( C, + function( C ) + + return List( (0):(Length( NerveData( C )[1][1] ) - 1 ), i -> CreateObject( C, i ) ); + + end ); + + ## + AddSetOfMorphismsOfFiniteCategory( C, + function( C ) + + return List( (0):(Length( NerveData( C )[1][2] ) - 1 ), i -> CreateMorphism( C, i ) ); + + end ); + + ## + AddSetOfGeneratingMorphismsOfCategory( C, + function( C ) + + return List( IndicesOfGeneratingMorphisms( C ), i -> CreateMorphism( C, i ) ); + + end ); + + ## + AddIsWellDefinedForObjects( C, + function( C, obj ) + local V, C0, obj_map; + + V = RangeCategoryOfHomomorphismStructure( C ); + + C0 = NerveData( C )[1][1]; + + obj_map = ObjectDatum( C, obj ); + + return IsWellDefinedForMorphisms( V, obj_map ) && + IsTerminal( V, Source( obj_map ) ) && + IsEqualForObjects( V, C0, Target( obj_map ) ); + + end ); + + ## + AddIsWellDefinedForMorphisms( C, + function( C, mor ) + local V, C1, mor_map; + + V = RangeCategoryOfHomomorphismStructure( C ); + + C1 = NerveData( C )[1][2]; + + mor_map = MorphismDatum( C, mor ); + + return IsWellDefinedForMorphisms( V, mor_map ) && + IsTerminal( V, Source( mor_map ) ) && + IsEqualForObjects( V, C1, Target( mor_map ) ); + + end ); + + ## + AddIsEqualForObjects( C, + function( C, obj_1, obj_2 ) + local V; + + V = RangeCategoryOfHomomorphismStructure( C ); + + return IsCongruentForMorphisms( V, ObjectDatum( C, obj_1 ), ObjectDatum( C, obj_2 ) ); + + end ); + + ## + AddIsEqualForMorphisms( C, + function( C, mor_1, mor_2 ) + local V; + + V = RangeCategoryOfHomomorphismStructure( C ); + + return IsEqualForMorphisms( V, MorphismDatum( C, mor_1 ), MorphismDatum( C, mor_2 ) ); + + end ); + + ## + AddIsCongruentForMorphisms( C, + function( C, mor_1, mor_2 ) + local V; + + V = RangeCategoryOfHomomorphismStructure( C ); + + return IsCongruentForMorphisms( V, MorphismDatum( C, mor_1 ), MorphismDatum( C, mor_2 ) ); + + end ); + + ## + AddIdentityMorphism( C, + function( C, obj ) + local V, id; + + V = RangeCategoryOfHomomorphismStructure( C ); + + id = NerveData( C )[2][1]; + + return MorphismConstructor( C, + obj, + PreCompose( V, ObjectDatum( C, obj ), id ), + obj ); + + end ); + + ## + AddPreCompose( C, + function( C, mor_1, mor_2 ) + local V, objs, mors, C2, s, t, ps, pt, mu, DC1xC1, C1xC1, C2_C1xC1, C1xC1_C2, mor_12; + + V = RangeCategoryOfHomomorphismStructure( C ); + + objs = NerveData( C )[1]; + mors = NerveData( C )[2]; + + ## Cβ‚‚ + C2 = objs[3]; + + ## s: C₁ β†’ Cβ‚€ + s = mors[2]; + + ## t: C₁ β†’ Cβ‚€ + t = mors[3]; + + ## pβ‚›: Cβ‚‚ β†’ C₁ + ps = mors[6]; + + ## pβ‚œ: Cβ‚‚ β†’ C₁ + pt = mors[7]; + + ## ΞΌ: Cβ‚‚ β†’ C₁ + mu = mors[8]; + + DC1xC1 = [ t, s ]; + + ## C₁ Γ—β‚œβ‚› C₁ + C1xC1 = FiberProduct( V, + DC1xC1 ); + + ## Cβ‚‚ β†’ C₁ Γ—β‚œβ‚› C₁ + C2_C1xC1 = UniversalMorphismIntoFiberProductWithGivenFiberProduct( V, + DC1xC1, + C2, + [ ps, pt ], + C1xC1 ); + + #% CAP_JIT_DROP_NEXT_STATEMENT + @Assert( 0, IsIsomorphism( V, C2_C1xC1 ) ); # the first condition for the simplicial set to be the nerve of a category + + ## C₁ Γ—β‚œβ‚› C₁ β†’ Cβ‚‚ + C1xC1_C2 = InverseForMorphisms( V, + C2_C1xC1 ); + + ## 1 β†’ C₁ Γ—β‚œβ‚› C₁ β†’ Cβ‚‚ + mor_12 = PreCompose( V, + UniversalMorphismIntoFiberProductWithGivenFiberProduct( V, + DC1xC1, + TerminalObject( V ), + [ MorphismDatum( C, mor_1 ), MorphismDatum( C, mor_2 ) ], + C1xC1 ), + C1xC1_C2 ); + + return MorphismConstructor( C, + Source( mor_1 ), + PreCompose( V, mor_12, mu ), + Target( mor_2 ) ); + + end ); + + @Assert( 0, IsIdenticalObj( V, RangeCategoryOfHomomorphismStructure( V ) ) ); + + ## + AddDistinguishedObjectOfHomomorphismStructure( C, + function( C ) + + return DistinguishedObjectOfHomomorphismStructure( RangeCategoryOfHomomorphismStructure( C ) ); + + end ); + + ## + AddHomomorphismStructureOnObjects( C, + function( C, obj_1, obj_2 ) + local V, mors, s, t, Hom_o1_C, Hom_C_o2; + + V = RangeCategoryOfHomomorphismStructure( C ); + + mors = NerveData( C )[2]; + + s = mors[2]; + t = mors[3]; + + Hom_o1_C = ProjectionInFactorOfFiberProduct( V, + [ s, ObjectDatum( C, obj_1 ) ], + 1 ); + + Hom_C_o2 = ProjectionInFactorOfFiberProduct( V, + [ t, ObjectDatum( C, obj_2 ) ], + 1 ); + + return FiberProduct( V, + [ Hom_o1_C, Hom_C_o2 ] ); + + end ); + + ## + AddHomomorphismStructureOnMorphismsWithGivenObjects( C, + function( C, source, phi_1, phi_2, range ) + local V, objs, mors, C2, s, t, ps, pt, mu, DC1xC1, C1xC1, C2_C1xC1, C1xC1_C2, + DC3, C3, p12, p23, pss, ptt, mux1, mumu, Hom_r1_s2, Hom_s1_r2, + phi_1xC2, C2xphi_2, iota; + + V = RangeCategoryOfHomomorphismStructure( C ); + + objs = NerveData( C )[1]; + mors = NerveData( C )[2]; + + ## Cβ‚‚ + C2 = objs[3]; + + ## s: C₁ β†’ Cβ‚€ + s = mors[2]; + + ## t: C₁ β†’ Cβ‚€ + t = mors[3]; + + ## pβ‚›: Cβ‚‚ β†’ C₁ + ps = mors[6]; + + ## pβ‚œ: Cβ‚‚ β†’ C₁ + pt = mors[7]; + + ## ΞΌ: Cβ‚‚ β†’ C₁ + mu = mors[8]; + + DC1xC1 = [ t, s ]; + + ## C₁ Γ—β‚œβ‚› C₁ + C1xC1 = FiberProduct( V, + DC1xC1 ); + + ## Cβ‚‚ β†’ C₁ Γ—β‚œβ‚› C₁ + C2_C1xC1 = UniversalMorphismIntoFiberProductWithGivenFiberProduct( V, + DC1xC1, + C2, + [ ps, pt ], + C1xC1 ); + + #% CAP_JIT_DROP_NEXT_STATEMENT + @Assert( 0, IsIsomorphism( V, C2_C1xC1 ) ); # the first condition for the simplicial set to be the nerve of a category + + ## C₁ Γ—β‚œβ‚› C₁ β†’ Cβ‚‚ + C1xC1_C2 = InverseForMorphisms( V, + C2_C1xC1 ); + + ## (pβ‚œ, pβ‚›) + DC3 = [ pt, ps ]; + + ## C₃ + C3 = FiberProduct( V, + DC3 ); + + ## p₁₂: C₃ β†’ Cβ‚‚ + p12 = ProjectionInFactorOfFiberProductWithGivenFiberProduct( V, + DC3, + 1, + C3 ); + + ## p₂₃: C₃ β†’ Cβ‚‚ + p23 = ProjectionInFactorOfFiberProductWithGivenFiberProduct( V, + DC3, + 2, + C3 ); + + ## pβ‚›β‚›: C₃ β†’ Cβ‚‚ + pss = PreCompose( V, p12, ps ); + + ## pβ‚œβ‚œ: C₃ β†’ Cβ‚‚ + ptt = PreCompose( V, p23, pt ); + + ## ΞΌ Γ— 1: C₃ β†’ C₁ Γ—β‚œβ‚› C₁ β†’ Cβ‚‚ + mux1 = PreCompose( V, + UniversalMorphismIntoFiberProductWithGivenFiberProduct( V, + DC1xC1, + C3, + [ PreCompose( V, p12, mu ), + ptt ], + C1xC1 ), + C1xC1_C2 ); + + ## ΞΌΞΌ: C₃ β†’ C₁ + mumu = PreCompose( V, mux1, mu ); + + ## Hom(r₁,sβ‚‚) β†ͺ C₁ + Hom_r1_s2 = MorphismFromFiberProductToSinkWithGivenFiberProduct( V, + [ ProjectionInFactorOfFiberProduct( V, + [ s, ObjectDatum( C, Target( phi_1 ) ) ], + 1 ), + ProjectionInFactorOfFiberProduct( V, + [ t, ObjectDatum( C, Source( phi_2 ) ) ], + 1 ) ], + source ); + + ## Hom(s₁,rβ‚‚) β†ͺ C₁ + Hom_s1_r2 = MorphismFromFiberProductToSinkWithGivenFiberProduct( V, + [ ProjectionInFactorOfFiberProduct( V, + [ s, ObjectDatum( C, Source( phi_1 ) ) ], + 1 ), + ProjectionInFactorOfFiberProduct( V, + [ t, ObjectDatum( C, Target( phi_2 ) ) ], + 1 ) ], + range ); + + ## [φ₁] Γ—β‚œβ‚› Hom(r₁,-) Γ—β‚œβ‚› Hom(-,-) β†ͺ C₃ + phi_1xC2 = ProjectionInFactorOfFiberProduct( V, + [ pss, MorphismDatum( C, phi_1 ) ], + 1 ); + + ## Hom(-,-) Γ—β‚œβ‚› Hom(-,sβ‚‚) Γ—β‚œβ‚› [Ο†β‚‚] β†ͺ C₃ + C2xphi_2 = ProjectionInFactorOfFiberProduct( V, + [ ptt, MorphismDatum( C, phi_2 ) ], + 1 ); + + ## ΞΉ: [φ₁] Γ—β‚œβ‚› Hom(r₁,sβ‚‚) Γ—β‚œβ‚› [Ο†β‚‚] β†ͺ C₃ β†’ C₁ + iota = PreCompose( V, + MorphismFromFiberProductToSink( V, + [ phi_1xC2, C2xphi_2 ] ), + mumu ); + + ## [φ₁] Γ—β‚œβ‚› Hom(r₁,sβ‚‚) Γ—β‚œβ‚› [Ο†β‚‚] β†’ Hom(s₁,rβ‚‚) + return LiftAlongMonomorphism( V, + Hom_s1_r2, + iota ); + + end ); + + ## + AddInterpretMorphismAsMorphismFromDistinguishedObjectToHomomorphismStructure( C, + function( C, mor ) + local V, mors, s, t, Hom_o1_C, Hom_C_o2, Hom_o1_o2; + + V = RangeCategoryOfHomomorphismStructure( C ); + + mors = NerveData( C )[2]; + + s = mors[2]; + t = mors[3]; + + Hom_o1_C = ProjectionInFactorOfFiberProduct( V, + [ s, ObjectDatum( C, Source( mor ) ) ], + 1 ); + + Hom_C_o2 = ProjectionInFactorOfFiberProduct( V, + [ t, ObjectDatum( C, Target( mor ) ) ], + 1 ); + + Hom_o1_o2 = MorphismFromFiberProductToSink( V, + [ Hom_o1_C, Hom_C_o2 ] ); + + return LiftAlongMonomorphism( V, + Hom_o1_o2, + MorphismDatum( C, mor ) ); + + end ); + + ## + AddInterpretMorphismFromDistinguishedObjectToHomomorphismStructureAsMorphism( C, + function( C, obj_1, obj_2, mor ) + local V, mors, s, t, Hom_o1_C, Hom_C_o2, Hom_o1_o2; + + V = RangeCategoryOfHomomorphismStructure( C ); + + mors = NerveData( C )[2]; + + s = mors[2]; + t = mors[3]; + + Hom_o1_C = ProjectionInFactorOfFiberProduct( V, + [ s, ObjectDatum( C, obj_1 ) ], + 1 ); + + Hom_C_o2 = ProjectionInFactorOfFiberProduct( V, + [ t, ObjectDatum( C, obj_2 ) ], + 1 ); + + Hom_o1_o2 = MorphismFromFiberProductToSink( V, + [ Hom_o1_C, Hom_C_o2 ] ); + + return MorphismConstructor( C, + obj_1, + PreCompose( V, + mor, + Hom_o1_o2 ), + obj_2 ); + + end ); + + #if false) + if (ValueOption( "no_precompiled_code" ) != true) + + ADD_FUNCTIONS_FOR_CategoryFromNerveDataPrecompiled( C ); + ADD_FUNCTIONS_FOR_CategoryFromNerveDataHomStructureOnMorphismsPrecompiled( C ); + + end; + + Finalize( C ); + + return C; + +end ); + +## +@InstallMethod( SetOfObjects, + "for a category from nerve data", + [ IsCategoryFromNerveData ], + + function( cat ) + + return SetOfObjectsOfCategory( cat ); + +end ); + +## +@InstallMethod( SetOfGeneratingMorphisms, + "for a category from nerve data", + [ IsCategoryFromNerveData ], + + function( cat ) + + return SetOfGeneratingMorphismsOfCategory( cat ); + +end ); + +## +@InstallMethod( Size, + "for a category from nerve data", + [ IsCategoryFromNerveData ], + + function( C ) + + return Length( NerveData( C )[1][2] ); + +end ); + +## +@InstallMethod( CreateObject, + "for a category from nerve data and an integer", + [ IsCategoryFromNerveData, IsBigInt ], + + function( C, o ) + local V, C0, obj_map; + + V = RangeCategoryOfHomomorphismStructure( C ); + + C0 = NerveData( C )[1][1]; + + obj_map = MorphismConstructor( V, + DistinguishedObjectOfHomomorphismStructure( C ), + [ o ], + C0 ); + + return ObjectConstructor( C, obj_map ); + +end ); + +## +@InstallMethod( /, + "for an integer and a category from nerve data", + [ IsBigInt, IsCategoryFromNerveData ], + + function( o, C ) + + return CreateObject( C, o ); + +end ); + +## +@InstallMethod( CreateMorphism, + "for two objects in a category from nerve data and an integer", + [ IsObjectInCategoryFromNerveData, IsBigInt, IsObjectInCategoryFromNerveData ], + + function( source, m, range ) + local C, V, C1, mor_map; + + C = CapCategory( source ); + + V = RangeCategoryOfHomomorphismStructure( C ); + + C1 = NerveData( C )[1][2]; + + mor_map = MorphismConstructor( V, + DistinguishedObjectOfHomomorphismStructure( C ), + [ m ], + C1 ); + + return MorphismConstructor( C, + source, + mor_map, + range ); + +end ); + +## +@InstallMethod( CreateMorphism, + "for a category from nerve data and an integer", + [ IsCategoryFromNerveData, IsBigInt ], + + function( C, m ) + local mors, s, t; + + mors = NerveData( C )[2]; + + s = mors[2]; + t = mors[3]; + + return CreateMorphism( + CreateObject( C, s( m ) ), + m, + CreateObject( C, t( m ) ) ); + +end ); + +## +@InstallMethod( /, + "for a string and category from nerve data", + [ IsString, IsCategoryFromNerveData ], + + function( name, C ) + local labels; + + labels = C.labels; + + if (name in labels[1]) + return CreateObject( C, -1 + SafePosition( labels[1], name ) ); + elseif (name in labels[2]) + return CreateMorphism( C, IndicesOfGeneratingMorphisms( C )[SafePosition( labels[2], name )] ); + elseif (name[1] in [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]) + return CreateMorphism( C, IntGAP( name ) ); + end; + + Error( "no object or morphism of name ", name, "\n" ); + +end ); + +#= comment for Julia +## +INSTALL_DOT_METHOD( IsCategoryFromNerveData ); +# =# + +## +@InstallMethod( OppositeNerveData, + "for a list", + [ IsList ], + + function( nerve_data ) + local objs, mors, C1, C2, V, + id, s, t, is, it, ps, pt, mu, + DC1_sxt_C1, C1_sxt_C1, pi_s, pi_t, C2_C1_sxt_C1, + DC1_txs_C1, C1_txs_C1, C2_C1_txs_C1, + C1_sxt_C1_C1_txs_C1, C1_txs_C1_C2, mu_op; + + objs = nerve_data[1]; + mors = nerve_data[2]; + + C1 = objs[2]; + C2 = objs[3]; + + V = CapCategory( C2 ); + + id = mors[1]; + s = mors[2]; + t = mors[3]; + is = mors[4]; + it = mors[5]; + ps = mors[6]; + pt = mors[7]; + mu = mors[8]; + + DC1_sxt_C1 = [ s, t ]; + + ## C₁ Γ—β‚›β‚œ C₁ + C1_sxt_C1 = FiberProduct( V, + DC1_sxt_C1 ); + + ## Cβ‚‚ β†’ C₁ Γ—β‚›β‚œ C₁ + C2_C1_sxt_C1 = UniversalMorphismIntoFiberProductWithGivenFiberProduct( V, + DC1_sxt_C1, + C2, + [ pt, ps ], + C1_sxt_C1 ); + + ## Ο€β‚›: C₁ Γ—β‚›β‚œ C₁ β†’ C₁ + pi_s = ProjectionInFactorOfFiberProductWithGivenFiberProduct( V, + DC1_sxt_C1, + 1, + C1_sxt_C1 ); + + ## Ο€β‚œ: C₁ Γ—β‚›β‚œ C₁ β†’ C₁ + pi_t = ProjectionInFactorOfFiberProductWithGivenFiberProduct( V, + DC1_sxt_C1, + 2, + C1_sxt_C1 ); + + DC1_txs_C1 = [ t, s ]; + + ## C₁ Γ—β‚œβ‚› C₁ + C1_txs_C1 = FiberProduct( V, + DC1_txs_C1 ); + + ## C₁ Γ—β‚›β‚œ C₁ β†’ C₁ Γ—β‚œβ‚› C₁ + C1_sxt_C1_C1_txs_C1 = UniversalMorphismIntoFiberProductWithGivenFiberProduct( V, + DC1_txs_C1, + C1_sxt_C1, + [ pi_t, pi_s ], + C1_txs_C1 ); + + ## Cβ‚‚ β†’ C₁ Γ—β‚œβ‚› C₁ + C2_C1_txs_C1 = UniversalMorphismIntoFiberProductWithGivenFiberProduct( V, + DC1_txs_C1, + C2, + [ ps, pt ], + C1_txs_C1 ); + + ## C₁ Γ—β‚œβ‚› C₁ β†’ Cβ‚‚ + C1_txs_C1_C2 = InverseForMorphisms( V, + C2_C1_txs_C1 ); + + ## Cβ‚‚ β†’ C₁ Γ—β‚›β‚œ C₁ β†’ C₁ Γ—β‚œβ‚› C₁ β†’ Cβ‚‚ β†’ C₁ + mu_op = PreComposeList( V, + C2, + [ C2_C1_sxt_C1, + C1_sxt_C1_C1_txs_C1, + C1_txs_C1_C2, + mu ], + C1 ); + + return PairGAP( objs, + @NTupleGAP( 8, + id, + t, + s, + it, + is, + pt, + ps, + mu_op ) ); + +end ); + +## +@InstallMethod( OppositeCategoryFromNerveData, + "for a category from nerve data", + [ IsCategoryFromNerveData ], + + function( C ) + local Cop, C_op; + + Cop = CategoryFromNerveData( + @rec( name = @Concatenation( "Opposite( ", Name( C ), " )" ), + ## the following nerve data is not "normalized", as it is not the result of the method NerveTruncatedInDegree2Data: + nerve_data = OppositeNerveData( NerveData( C ) ), + indices_of_generating_morphisms = IndicesOfGeneratingMorphisms( C ), + decomposition_of_all_morphisms = TransposedMat( List( DecompositionIndicesOfAllMorphisms( C ), s -> List( s, t -> List( t, Reversed ) ) ) ), + relations = List( RelationsAmongGeneratingMorphisms( C ), pair -> PairGAP( Reversed( pair[1] ), Reversed( pair[2] ) ) ), + labels = C.labels, + properties = ListKnownCategoricalProperties( Opposite( C ) ) ) ); + + @Assert( 0, IsIdenticalObj( IndicesOfGeneratingMorphisms( Cop ), IndicesOfGeneratingMorphisms( C ) ) ); + + ## now construct the "normalized" opposite category + C_op = CategoryFromNerveData( + @rec( name = Name( Cop ), + ## now the "normalized" data tables + nerve_data = CallFuncListAtRuntime( NerveTruncatedInDegree2Data, [ Cop ] ), + indices_of_generating_morphisms = CallFuncListAtRuntime( IndicesOfGeneratingMorphismsFromHomStructure, [ Cop ] ), + decomposition_of_all_morphisms = CallFuncListAtRuntime( DecompositionIndicesOfAllMorphisms, [ Cop ] ), + relations = RelationsAmongGeneratingMorphisms( Cop ), + labels = Cop.labels, + properties = ListKnownCategoricalProperties( Cop ) ) ); + + SetOppositeCategoryFromNerveData( C_op, C ); + + return C_op; + +end ); + +## +@InstallMethod( DataTablesOfCategory, + "for a category from nerve data", + [ IsCategoryFromNerveData ], + + function( C ) + local V, T, nerve_data, objs, mors, C0, C1, s, t, + identity_data, + precompose, precompose_data, + hom_on_objs, hom_on_objs_data, + hom_on_mors, hom_on_mors_data, + introduction, introduction_data, + elimination, elimination_data; + + V = RangeCategoryOfHomomorphismStructure( C ); + + T = DistinguishedObjectOfHomomorphismStructure( C ); + + nerve_data = NerveData( C ); + + objs = nerve_data[1]; + mors = nerve_data[2]; + + C0 = objs[1]; + C1 = objs[2]; + + s = mors[2]; + t = mors[3]; + + identity_data = AsList( mors[1] ); + + precompose = + function( i, j ) + + if (@not t( i ) == s( j )) + return -1; + end; + + return MorphismDatum( C, + PreCompose( C, + CreateMorphism( C, i ), + CreateMorphism( C, j ) ) )( 0 ); + + end; + + precompose_data = + List( (0):(Length( C1 ) - 1), i -> + List( (0):(Length( C1 ) - 1), j -> + precompose( i, j ) ) ); + + hom_on_objs = + function( i, j ) + + return ObjectDatum( V, + HomomorphismStructureOnObjects( C, + CreateObject( C, i ), + CreateObject( C, j ) ) ); + + end; + + hom_on_objs_data = + List( (0):(Length( C0 ) - 1), i -> + List( (0):(Length( C0 ) - 1), j -> + hom_on_objs( i, j ) ) ); + + hom_on_mors = + function( i, j ) + + return MorphismDatum( V, + HomomorphismStructureOnMorphisms( C, + CreateMorphism( C, i ), + CreateMorphism( C, j ) ) ); + + end; + + hom_on_mors_data = + List( (0):(Length( C1 ) - 1), i -> + List( (0):(Length( C1 ) - 1), j -> + hom_on_mors( i, j ) ) ); + + introduction = + function( i ) + + return MorphismDatum( V, + InterpretMorphismAsMorphismFromDistinguishedObjectToHomomorphismStructure( C, + CreateMorphism( C, i ) ) ); + + end; + + introduction_data = + List( (0):(Length( C1 ) - 1), i -> + introduction( i ) ); + + elimination = + function( i, j, k ) + + return MorphismDatum( C, + InterpretMorphismFromDistinguishedObjectToHomomorphismStructureAsMorphism( C, + CreateObject( C, i ), + CreateObject( C, j ), + MorphismConstructor( V, + T, + [ k ], + ObjectConstructor( V, + hom_on_objs( i, j ) ) ) ) )( 0 ); + + end; + + elimination_data = + List( (0):(Length( C0 ) - 1), i -> + List( (0):(Length( C0 ) - 1), j -> + List( (0):(hom_on_objs( i, j ) - 1), k -> + elimination( i, j, k ) ) ) ); + + return PairGAP( PairGAP( + Length( C0 ), + Length( C1 ) ), + @NTupleGAP( 8, + identity_data, + AsList( s ), + AsList( t ), + precompose_data, + hom_on_objs_data, + hom_on_mors_data, + introduction_data, + elimination_data ) ); + +end ); + +#################################### +# +# View, Print, and Display methods: +# +#################################### + +## +@InstallMethod( ViewString, + "for an object in a category from nerve data", + [ IsObjectInCategoryFromNerveData ], + + function( obj ) + + return @Concatenation( "<(", CapCategory( obj ).labels[1][1 + MapOfObject( obj )( 0 )], ")>" ); + +end ); + +## +@InstallMethod( ViewString, + "for a morphism in a category from nerve data", + [ IsMorphismInCategoryFromNerveData ], + + function( mor ) + local C, labels, s, t, i, pos; + + C = CapCategory( mor ); + + labels = C.labels; + + s = MapOfObject( Source( mor ) )( 0 ); + t = MapOfObject( Target( mor ) )( 0 ); + + i = MapOfMorphism( mor )( 0 ); + + pos = Position( IndicesOfGeneratingMorphisms( C ), i ); + + if (IsInt( pos )) + pos = labels[2][pos]; + else + pos = Position( AsList( NerveData( C )[2][1] ), i ); + if (IsInt( pos )) + pos = labels[1][pos]; + else + pos = JoinStringsWithSeparator( + List( DecompositionIndicesOfAllMorphisms( C )[1+t][1+s][1 + HomStructure( mor )(0)], i -> labels[2][1 + i] ), + "β‹…" ); + end; + end; + + return @Concatenation( + "(", labels[1][1 + s], ")", + "-[(", pos, ")]β†’", + "(", labels[1][1 + t], ")" ); + +end ); + +## +@InstallMethod( PrintObj, + "for an object in a category from nerve data", + [ IsObjectInCategoryFromNerveData ], + + function( obj ) + + ViewObj( obj ); + Print( "\n" ); + +end ); + +## +@InstallMethod( PrintObj, + "for a morphism in a category from nerve data", + [ IsMorphismInCategoryFromNerveData ], + + function( mor ) + + ViewObj( mor ); + Print( "\n" ); + +end ); + +## +@InstallMethod( DisplayString, + "for an object in a category from nerve data", + [ IsObjectInCategoryFromNerveData ], + + function( obj ) + + return @Concatenation( ViewString( obj ), "\n" ); + +end ); + +## +@InstallMethod( DisplayString, + "for a morphism in a category from nerve data", + [ IsMorphismInCategoryFromNerveData ], + + function( mor ) + + return @Concatenation( ViewString( mor ), "\n" ); + +end ); + +## +@InstallMethod( LaTeXOutput, + "for an object in a category from nerve data", + [ IsObjectInCategoryFromNerveData ], + + function( obj ) + + return StringGAP( MapOfObject( obj )( 0 ) ); + +end ); + +## +@InstallMethod( LaTeXOutput, + "for a morphism in a category from nerve data", + [ IsMorphismInCategoryFromNerveData ], + + function( mor ) + local s; + + s = StringGAP( MapOfMorphism( mor )( 0 ) ); + + if (ValueOption( "OnlyDatum" ) == true) + + return s; + + end; + + return @Concatenation( + "[", LaTeXOutput( Source( mor ) ), "]", + "-\\left[[", s, "]\\right]\\rightarrow", + "[", LaTeXOutput( Target( mor ) ), "]" ); + +end ); diff --git a/FpCategories/src/gap/GroebnerBasesForPathCategories.gd.autogen.jl b/FpCategories/src/gap/GroebnerBasesForPathCategories.gd.autogen.jl new file mode 100644 index 0000000..996851a --- /dev/null +++ b/FpCategories/src/gap/GroebnerBasesForPathCategories.gd.autogen.jl @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# FpCategories: Finitely presented categories by generating quivers and relations +# +# Declarations +# + +#! @Chapter Path categories + +#################################### +# +#! @Section Operations +# +#################################### + +#! @Description +#! The input is a path category C and a list rels consisting of pairs of parallel morphisms in C. +#! The output is the Groebner basis of rels. +#! @Arguments C, rels +#! @Returns a dense list +@DeclareOperation( "GroebnerBasis", [ IsPathCategory, IsDenseList ] ); + +#! @Description +#! The input is a path category C and a Groebner basis groebner_basis consisting of pairs of parallel morphisms in C. +#! The output is the reduced Groebner basis of groebner_basis. +#! @Arguments C, groebner_basis +#! @Returns a dense list +@DeclareOperation( "ReducedGroebnerBasisWithGivenGroebnerBasis", [ IsPathCategory, IsDenseList ] ); + +#! @Description +#! The input is a path category C and a list rels consisting of pairs of parallel morphisms in C. +#! The output is the reduced Groebner basis of rels. +#! @Arguments C, rels +#! @Returns a dense list +@DeclareOperation( "ReducedGroebnerBasis", [ IsPathCategory, IsDenseList ] ); + +#! @Description +#! The input is a path category C, two parallel morphisms f, g and a string +#! admissible_order which takes one of the following two values "Dp" or "dp". +#! The output is whether f $\succ$ g with respect to the specified admissible order. +#! "Dp" stands for the left-length-lexicographic order under which f $\succ_[\mathtt[Dp]]$ g if +#! MorphismLength(f) $\succ$ MorphismLength(g); +#! or MorphismLength(f)$=$MorphismLength(g) and the first nonzero entry in +#! MorphismIndices(f)$-$MorphismIndices(g) is negative. +#! "dp" stands for the right-length-lexicographic order under which f $\succ_[\mathtt[dp]]$ g if +#! MorphismLength(f) $\succ$ MorphismLength(g); +#! or MorphismLength(f)$=$MorphismLength(g) and the last nonzero entry in +#! MorphismIndices(f)$-$MorphismIndices(g) is negative. For example, if +#! the quiver of C is defined by the string "(*)[x:*->*,y:*->*]",) +#! - $x^2 \succ_[\mathtt[Dp]] xy \succ_[\mathtt[Dp]] yx \succ_[\mathtt[Dp]] y^2 \succ_[\mathtt[Dp]] x \succ_[\mathtt[Dp]] y \succ_[\mathtt[Dp]] \mathtt[id(*)]$ +#! - $x^2 \succ_[\mathtt[dp]] yx \succ_[\mathtt[dp]] xy \succ_[\mathtt[dp]] y^2 \succ_[\mathtt[dp]] x \succ_[\mathtt[dp]] y \succ_[\mathtt[dp]] \mathtt[id(*)]$ +#! @Arguments C, f, g, admissible_order +#! @Returns a boolean +@DeclareOperation( "IsDescendingForMorphisms", [ IsPathCategory, IsPathCategoryMorphism, IsPathCategoryMorphism, IsString ] ); + +#! @Description +#! The input is a path category C, two parallel morphisms f, g and a string +#! admissible_order which takes one of the following two values "Dp" or "dp". +#! The output is whether f $\prec$ g with respect to the specified admissible order. +#! @Arguments C, f, g, admissible_order +#! @Returns a boolean +@DeclareOperation( "IsAscendingForMorphisms", [ IsPathCategory, IsPathCategoryMorphism, IsPathCategoryMorphism, IsString ] ); + +@DeclareOperation( "ReductionOfMorphism", [ IsPathCategory, IsPathCategoryMorphism, IsDenseList ] ); + +# @Description +# The input is a path category C and two morphisms f$:A \to B$, g$:C \to D$. +# The output is the list of all pairs of following form: +# - $[[l:C \to A,\mathtt[id](B)],[\mathtt[id](C),r:D \to B]]$ with $lf=gr$ and the left-end of $f$ intersects nontrivially with the right-end of $g$. +# - $[[\mathtt[id](A),r:B \to D],[l:A \to C,\mathtt[id](D)]]$ with $fr=lg$ and the right-end of $f$ intersects nontrivially with the left-end of $g$. +# - $[[\mathtt[id](A),\mathtt[id](B)],[l:A \to C,r:D \to B]]$ with $f=lgr$ and $f$ contains $g$. +# - $[[l:C \to A,r:B \to D],[\mathtt[id](C),\mathtt[id](D)]]$ with $lfr=g$ and $g$ contains $f$. +# @Arguments C, f, g +# @Returns a list of pairs of pairs +@DeclareOperation( "OverlappingCoefficients", [ IsPathCategory, IsPathCategoryMorphism, IsPathCategoryMorphism ] ); + +@DeclareOperation( "NewRelation", [ IsPathCategory, IsDenseList, IsDenseList, IsDenseList ] ); + diff --git a/FpCategories/src/gap/GroebnerBasesForPathCategories.gi.autogen.jl b/FpCategories/src/gap/GroebnerBasesForPathCategories.gi.autogen.jl new file mode 100644 index 0000000..4f1c983 --- /dev/null +++ b/FpCategories/src/gap/GroebnerBasesForPathCategories.gi.autogen.jl @@ -0,0 +1,273 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# FpCategories: Finitely presented categories by generating quivers and relations +# +# Implementations +# + + +########################## +# +# Categorical Relations +# +########################## + +## For each g in G, we must have g[1] > g[2], otherwise it might never terminate. +## The output is a morphism r < f such that r & f are congruent modulo G + +## +@InstallMethod( ReductionOfMorphism, + [ IsPathCategory, IsPathCategoryMorphism, IsDenseList ], + + function ( C, f, G ) + local Q, G_datum, predicate, func, initial_value; + + Q = UnderlyingQuiver( C ); + + G_datum = List( G, g -> PairGAP( MorphismLength( g[1] ), MorphismIndices( g[1] ) ) ); + + predicate = ( mor_1, mor_2 ) -> MorphismIndices( mor_1 ) == MorphismIndices( mor_2 ); + + func = + function ( f ) + local f_datum, i, g_datum, j, u, v; + + f_datum = PairGAP( MorphismLength( f ), MorphismIndices( f ) ); + + i = PositionProperty( G_datum, g_datum -> f_datum[1] >= g_datum[1] && PositionSublist( f_datum[2], g_datum[2] ) != fail ); + + if (i == fail) + + return f; + + else + + g_datum = G_datum[i]; + + j = PositionSublist( f_datum[2], g_datum[2] ); + + return MorphismConstructor( C, + Source( f ), + PairGAP( First( f_datum ) - First( g_datum ) + MorphismLength( G[i][2] ), + @Concatenation( f_datum[2][ (1):(j - 1) ], MorphismIndices( G[i][2] ), f_datum[2][ (j + First( g_datum )):(First( f_datum )) ] ) ), + Target( f ) ); + + end; + + end; + + initial_value = f; + + return CapFixpoint( predicate, func, initial_value ); + +end ); + +## +## all pairs [ [l_g, r_g], [l_h, r_h] ] which satisfy l_g*g*r_g == l_h*h*r_h +## +@InstallMethod( OverlappingCoefficients, + [ IsPathCategory, IsPathCategoryMorphism, IsPathCategoryMorphism ], + + function ( C, f, g ) + local Q, l_f, i_f, l_g, i_g, pos, overlaps_on_left_of_g, overlaps_on_right_of_g, inner_overlaps; + + Q = UnderlyingQuiver( C ); + + l_f = MorphismLength( f ); + i_f = MorphismIndices( f ); + + l_g = MorphismLength( g ); + i_g = MorphismIndices( g ); + + pos = PositionsProperty( (1):(Minimum( l_f, l_g )), + i -> (i != l_f || i != l_g) && i_g[(l_g - i + 1):(l_g)] == i_f[(1):(i)] ); + + overlaps_on_left_of_g = + List( pos, + i -> PairGAP( + PairGAP( + MorphismConstructor( C, Source( g ), PairGAP( l_g - i, i_g[(1):(l_g - i)] ), Source( f ) ), + IdentityMorphism( C, Target( f ) ) ), + PairGAP( + IdentityMorphism( C, Source( g ) ), + MorphismConstructor( C, Target( g ), PairGAP( l_f - i, i_f[(i + 1):(l_f)] ), Target( f ) ) ) ) ); + + pos = PositionsProperty( (1):(Minimum( l_f, l_g )), + i -> ( i != l_f || i != l_g ) + && i_f[(l_f - i + 1):(l_f)] == i_g[(1):(i)] ); + + overlaps_on_right_of_g = + List( pos, + i -> PairGAP( + PairGAP( + IdentityMorphism( C, Source( f ) ), + MorphismConstructor( C, Target( f ), PairGAP( l_g - i, i_g[(i + 1):(l_g)] ), Target( g ) ) ), + PairGAP( + MorphismConstructor( C, Source( f ), PairGAP( l_f - i, i_f[(1):(l_f - i)] ), Source( g ) ), + IdentityMorphism( C, Target( g ) ) ) ) ); + + if (l_f >= l_g) + + inner_overlaps = + List( PositionsOfSublist( i_f, i_g ), + i -> PairGAP( + PairGAP( + IdentityMorphism( C, Source( f ) ), + IdentityMorphism( C, Target( f ) ) ), + PairGAP( + MorphismConstructor( C, Source( f ), PairGAP( i - 1, i_f[(1):(i - 1)] ), Source( g ) ), + MorphismConstructor( C, Target( g ), PairGAP( l_f - i - l_g + 1, i_f[(i + l_g):(l_f)] ), Target( f ) ) ) ) ); + + return @Concatenation( inner_overlaps, overlaps_on_left_of_g, overlaps_on_right_of_g ); + + else + + inner_overlaps = + List( PositionsOfSublist( i_g, i_f ), + i -> PairGAP( + PairGAP( + MorphismConstructor( C, Source( g ), PairGAP( i - 1, i_g[(1):(i - 1)] ), Source( f ) ), + MorphismConstructor( C, Target( f ), PairGAP( l_g - i - l_f + 1, i_g[(i + l_f):(l_g)] ), Target( g ) ) ), + PairGAP( + IdentityMorphism( C, Source( g ) ), + IdentityMorphism( C, Target( g ) ) ) ) ); + + return @Concatenation( inner_overlaps, overlaps_on_left_of_g, overlaps_on_right_of_g ); + + end; + +end ); + +## +@InstallMethod( NewRelation, + [ IsPathCategory, IsDenseList, IsDenseList, IsDenseList ], + + function ( C, rel_1, rel_2, overlap_coeffs ) + local m1, m2; + + #@Assert( 0, IsEqualForMorphisms( C, + # PreComposeList( C, [ overlap_coeffs[1][1], rel_1[1], overlap_coeffs[1][2] ] ), + # PreComposeList( C, [ overlap_coeffs[2][1], rel_2[1], overlap_coeffs[2][2] ] ) ) ); + + m1 = PreComposeList( C, [ overlap_coeffs[1][1], rel_1[2], overlap_coeffs[1][2] ] ); + m2 = PreComposeList( C, [ overlap_coeffs[2][1], rel_2[2], overlap_coeffs[2][2] ] ); + + if (IsAscendingForMorphisms( C, m1, m2 )) + return PairGAP( m2, m1 ); + else + return PairGAP( m1, m2 ); + end; + +end ); + +## +@InstallMethod( GroebnerBasis, + [ IsPathCategory, IsDenseList ], + + function ( C, relations ) + local gb, indices, rels, i, g1, g2, new_rels; + + gb = List( (1):(Length( relations )), i -> List( [ 1, 2 ], j -> relations[i][j] ) ); + + for i in (1):(Length( gb )) + gb[i] = SortedList( gb[i], ( g1, g2 ) -> IsAscendingForMorphisms( C, g2, g1 ) ); + end; + + indices = UnorderedTuples( (1):(Length( gb )), 2 ); + + rels = @Concatenation( List( indices, + i -> List( OverlappingCoefficients( C, gb[i[1]][1], gb[i[2]][1] ), + overlap_coeffs -> NewRelation( C, gb[i[1]], gb[i[2]], overlap_coeffs ) ) ) ); + + i = 1; + + while i <= Length( rels ) + + if (@not IsEqualForMorphisms( C, rels[i][1], rels[i][2] )) + + g1 = ReductionOfMorphism( C, rels[i][1], gb ); + g2 = ReductionOfMorphism( C, rels[i][2], gb ); + + if (@not IsEqualForMorphisms( C, g1, g2 )) + + if (IsAscendingForMorphisms( C, g1, g2 )) + Add( gb, PairGAP( g2, g1 ) ); + else + Add( gb, PairGAP( g1, g2 ) ); + end; + + indices = Cartesian( (1):(Length( gb )), [ Length( gb ) ] ); + + new_rels = + @Concatenation( + List( indices, + i -> List( OverlappingCoefficients( C, gb[i[1]][1], gb[i[2]][1] ), + overlap_coeffs -> NewRelation( C, gb[i[1]], gb[i[2]], overlap_coeffs ) ) ) ); + + rels = @Concatenation( rels, new_rels ); + + end; + + end; + + i = i + 1; + + end; + + return gb; + +end ); + +## +@InstallMethod( ReducedGroebnerBasisWithGivenGroebnerBasis, + [ IsPathCategory, IsDenseList ], + + function ( C, gb ) + local reduced_gb, i, H, r1, r2; + + reduced_gb = ShallowCopy( gb ); + + i = 1; + + while i <= Length( reduced_gb ) + + H = @Concatenation( reduced_gb[ (1):(i-1) ], reduced_gb[ (i+1):(Length( reduced_gb )) ] ); + + r1 = ReductionOfMorphism( C, reduced_gb[i][1], H ); + r2 = ReductionOfMorphism( C, reduced_gb[i][2], H ); + + if (IsEqualForMorphisms( C, r1, r2 )) + + Remove( reduced_gb, i ); + + elseif (!(IsEqualForMorphisms( C, r1, reduced_gb[i][1] )) || @not IsEqualForMorphisms( C, r2, reduced_gb[i][2] )) + + if (IsAscendingForMorphisms( C, r1, r2 )) + reduced_gb[i] = [ r2, r1 ]; + else + reduced_gb[i] = [ r1, r2 ]; + end; + + i = 1; + + else + + i = i + 1; + + end; + + end; + + return reduced_gb; + +end ); + +## +@InstallMethod( ReducedGroebnerBasis, + [ IsPathCategory, IsDenseList ], + + function ( C, relations ) + + return ReducedGroebnerBasisWithGivenGroebnerBasis( C, GroebnerBasis( C, relations ) ); + +end ); + diff --git a/FpCategories/src/gap/Julia.gi.autogen.jl b/FpCategories/src/gap/Julia.gi.autogen.jl new file mode 100644 index 0000000..eda3e39 --- /dev/null +++ b/FpCategories/src/gap/Julia.gi.autogen.jl @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# FpCategories: Finitely presented categories by generating quivers and relations +# +# Implementations +# + +## +@InstallMethod( FinQuiver, + [ IsJuliaObject ], + + function( description ) + + return FinQuiver( JuliaToGAP( IsString, description ) ); + +end ); diff --git a/FpCategories/src/gap/PathCategories.gd.autogen.jl b/FpCategories/src/gap/PathCategories.gd.autogen.jl new file mode 100644 index 0000000..19bf1ad --- /dev/null +++ b/FpCategories/src/gap/PathCategories.gd.autogen.jl @@ -0,0 +1,202 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# FpCategories: Finitely presented categories by generating quivers and relations +# +# Declarations +# + +#! @Chapter Path categories + +#################################### +# +#! @Section GAP categories +# +#################################### + +#! @Description +#! The &GAP; category of path categories. +@DeclareFilter( "IsPathCategory", + IsCapCategory ); + +#! @Description +#! The &GAP; category of objects in path categories. +@DeclareFilter( "IsPathCategoryObject", + IsCapCategoryObject ); + +#! @Description +#! The &GAP; category of morphisms in path categories. +@DeclareFilter( "IsPathCategoryMorphism", + IsCapCategoryMorphism ); + +#################################### +# +#! @Section Constructors +# +#################################### + +#! @Description +#! The input is a &CAP; quiver q. +#! The output is the path category of q, i.e., the category whose objects are the objects of q +#! and whose morphisms are lists of morphisms in q, in which the target of any morphism +#! is equal to the source of the next morphism. +#! @Arguments q +#! @Returns a &CAP; category +@DeclareOperation( "PathCategory", [ IsFinQuiver ] ); + + +if (false) +#! @Description +#! The input is a path category C of &CAP; quiver $q$ and a positive integer i. +#! The output is the i'th object in C. +#! @Arguments C, i +#! @Returns a &CAP; category object +@DeclareOperation( "ObjectConstructor", [ IsPathCategory, IsBigInt ] ); + +#! @Description +#! The input is a path category C of &CAP; quiver $q$, two objects s, t +#! a nonnegative integer length and a list support of length l +#! consisting of morphisms in $q$ where the target of each morphism is equal to the source of the next morphism. +#! The output is the morphism in C whose length is l and whose support is support. +#! @Arguments C, s, l, support, t +#! @Returns a &CAP; category morphism +@DeclareOperation( "MorphismConstructor", [ IsPathCategory, IsPathCategoryObject, IsBigInt, IsDenseList, IsPathCategoryObject ] ); +end; + +#! @Description +#! Assigns the objects of C to global variables. +#! Names of the variables are the concatenation of str with the labels of the objects. +#! The default value of str is the empty string. +#! @Arguments C [, str] +#! @Returns nothing +@DeclareOperation( "AssignSetOfObjects", [ IsPathCategory, IsString ] ); + +#! @Description +#! Assigns the generating morphisms of C to global variables. +#! Names of the variables are the concatenation of str with the labels of the generating morphisms. +#! The default value of str is the empty string. +#! @Arguments C [, str] +#! @Returns nothing +@DeclareOperation( "AssignSetOfGeneratingMorphisms", [ IsPathCategory, IsString ] ); + +#################################### +# +#! @Section Attributes +# +#################################### + +#! @Description +#! Returns the opposite category of the path category C. +#! @Arguments C +#! @Returns a path category +@DeclareAttribute( "OppositePathCategory", IsPathCategory ); + +#! @Arguments C +@DeclareAttribute( "CategoryFromNerveData", IsPathCategory ); + +#! @Description +#! Returns the defining quiver of the path category C. +#! @Arguments C +#! @Returns a list of &CAP; category objects +@DeclareAttribute( "UnderlyingQuiver", IsPathCategory ); + +CapJitAddTypeSignature( "UnderlyingQuiver", [ IsPathCategory ], + function ( input_types ) + + return CapJitDataTypeOfCategory( UnderlyingQuiver( input_types[1].category ) ); + +end ); + +#! @Description +#! Returns the index of the object v. +#! @Arguments v +#! @Returns a positive integer +@DeclareAttribute( "ObjectIndex", IsPathCategoryObject ); + +CapJitAddTypeSignature( "ObjectIndex", [ IsPathCategoryObject ], IsBigInt ); + +@DeclareAttribute( "UnderlyingQuiverObject", IsPathCategoryObject ); + +#! @Description +#! Returns the label of the object v. +#! @Arguments v +#! @Returns a string +@DeclareAttribute( "ObjectLabel", IsPathCategoryObject ); + +#! @Description +#! Returns the length of alpha. +#! @Arguments alpha +#! @Returns a positive integer +@DeclareAttribute( "MorphismLength", IsPathCategoryMorphism ); + +CapJitAddTypeSignature( "MorphismLength", [ IsPathCategoryMorphism ], IsBigInt ); + +#! @Description +#! Returns the list of morphisms in the underlying quiver which defines alpha. +#! @Arguments alpha +#! @Returns a dense-list of &CAP; quiver morphisms +@DeclareAttribute( "MorphismSupport", IsPathCategoryMorphism ); + +#! @Description +#! Returns the indices of the morphisms in MorphismSupport(alpha). +#! @Arguments alpha +#! @Returns a dense-list of positive integers +@DeclareAttribute( "MorphismIndices", IsPathCategoryMorphism ); + +CapJitAddTypeSignature( "MorphismIndices", [ IsPathCategoryMorphism ], CapJitDataTypeOfListOf( IsBigInt ) ); + +#! @Description +#! Returns the label of the morphism alpha. +#! @Arguments alpha +#! @Returns a positive integer +@DeclareAttribute( "MorphismLabel", IsPathCategoryMorphism ); + +@DeclareAttribute( "DecompositionIndicesOfMorphism", + IsPathCategoryMorphism ); + +@DeclareAttribute( "DecompositionOfMorphismInCategory", + IsPathCategoryMorphism ); + +#! @Description +#! Returns whether C can be enriched over the category of finite sets. +#! @Arguments C +#! @Returns a boolean +@DeclareProperty( "IsFinitePathCategory", IsPathCategory ); + +#! @Description +#! The input is a path category C and a list of morphisms mors in C +#! (mors is usually the leading terms of a Groebner basis). +#! The output is whether almost all morphisms of C are multiples of elements in mors. +#! In other words, whether the number of morphisms that are not multiples of elements in mors (i.e., Macaulay monomials) is finite. +#! @Arguments C, mors +#! @Returns a boolean +@DeclareOperation( "HasFiniteNumberOfMacaulayMorphisms", [ IsPathCategory, IsDenseList ] ); + +#! @Description +#! The input is a path category C and a list of morphisms mors in C +#! (mors is usually the leading terms of a Groebner basis). +#! The output is the Macaulay monomials with respect to mors. +#! @Arguments C, mors +#! @Returns a boolean +@DeclareOperation( "MacaulayMorphisms", [ IsPathCategory, IsDenseList ] ); + +@KeyDependentOperation( "ExternalHomsWithGivenLengthData", IsPathCategory, IsBigInt, ReturnTrue ); +@KeyDependentOperation( "ExternalHomsWithGivenLength", IsCapCategory, IsBigInt, ReturnTrue ); +@DeclareAttribute( "ExternalHoms", IsPathCategory ); + +@DeclareAttribute( "RelationsAmongGeneratingMorphisms", + IsPathCategory ); + +#################################### +# +#! @Section Operations +# +#################################### + +@DeclareOperation( "ExtendFunctorToFpCategoryData", + [ IsPathCategory, IsList, IsCapCategory ] ); + +@DeclareOperation( "ExtendContravariantFunctorToFpCategoryData", + [ IsPathCategory, IsList, IsCapCategory ] ); + +@DeclareGlobalFunction( "FpCategories_SORT_MORPHISMS_LIKE_QPA" ); + +@DeclareGlobalFunction( "CAP_INTERNAL_EXTRACT_STRING_OF_PATH" ); diff --git a/FpCategories/src/gap/PathCategories.gi.autogen.jl b/FpCategories/src/gap/PathCategories.gi.autogen.jl new file mode 100644 index 0000000..35fabc6 --- /dev/null +++ b/FpCategories/src/gap/PathCategories.gi.autogen.jl @@ -0,0 +1,1487 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# FpCategories: Finitely presented categories by generating quivers and relations +# +# Implementations +# + +## +@InstallMethod( PathCategory, + [ IsFinQuiver ], + + @FunctionWithNamedArguments( + [ + [ "admissible_order", fail ], + [ "FinalizeCategory", false ], + [ "range_of_HomStructure", fail ], + ], + function( CAP_NAMED_ARGUMENTS, q ) + local name, C, range_cat; + + name = @Concatenation( "PathCategory( ", Name( q ), " )" ); + + C = CreateCapCategoryWithDataTypes( name, + IsPathCategory, + IsPathCategoryObject, + IsPathCategoryMorphism, + IsCapCategoryTwoCell, + IsBigInt, + CapJitDataTypeOfNTupleOf( 2, + IsBigInt, + CapJitDataTypeOfListOf( IsBigInt ) ), + fail + ; overhead = false ); + + C.category_as_first_argument = true; + + if (admissible_order == fail) + + C.admissible_order = "dp"; + + else + + C.admissible_order = admissible_order; + + end; + + SetIsFinitelyPresentedCategory( C, true ); + + SetUnderlyingQuiver( C, q ); + + SetDefiningTripleOfUnderlyingQuiver( C, + Triple( NumberOfObjects( q ), + NumberOfMorphisms( q ), + ListN( IndicesOfSources( q ), IndicesOfTargets( q ), ( s, t ) -> PairGAP( -1 + s, -1 + t ) ) ) ); + + C.compiler_hints = + @rec( category_attribute_names = + [ "UnderlyingQuiver", + "DefiningTripleOfUnderlyingQuiver", + ], + ); + + ## + AddObjectConstructor( C, + function ( C, obj_index ) + + return SetOfObjects( C )[obj_index]; + + end ); + + ## + AddObjectDatum( C, + function ( C, obj ) + + return ObjectIndex( obj ); + + end ); + + ## + AddIsWellDefinedForObjects( C, + function ( C, obj ) + + return true; + + end ); + + ## + AddIsEqualForObjects( C, + function ( C, obj_1, obj_2 ) + + return IsIdenticalObj( obj_1, obj_2 ); + + end ); + + ## + AddMorphismConstructor( C, + function ( C, source, datum, target ) + + #% CAP_JIT_DROP_NEXT_STATEMENT + @Assert( 0, ForAll( datum[2], IsBigInt ) ); + + return CreateCapCategoryMorphismWithAttributes( C, + source, target, + MorphismLength, datum[1], + MorphismIndices, datum[2] ); + + end ); + + ## + AddMorphismDatum( C, + function ( C, mor ) + + return PairGAP( MorphismLength( mor ), MorphismIndices( mor ) ); + + end ); + + ## + AddIsWellDefinedForMorphisms( C, + function ( C, mor ) + local q, l, s; + + q = UnderlyingQuiver( C ); + + l = MorphismLength( mor ); + s = MorphismSupport( mor ); + + return l == Length( s ) && + ( ( l == 0 && IsEndomorphism( C, mor ) ) || + ( ObjectIndex( Source( mor ) ) == ObjectIndex( Source( First( s ) ) ) && + ObjectIndex( Target( mor ) ) == ObjectIndex( Target( Last( s ) ) ) ) ) && + ForAll( (1):(l - 1), j -> Target( s[j] ) == Source( s[j+1] ) ); + + end ); + + ## + AddIsEqualForMorphisms( C, + function ( C, mor_1, mor_2 ) + + return IsEqualForObjects( C, Source( mor_1 ), Source( mor_2 ) ) && + IsEqualForObjects( C, Target( mor_1 ), Target( mor_2 ) ) && + MorphismLength( mor_1 ) == MorphismLength( mor_2 ) && + MorphismIndices( mor_1 ) == MorphismIndices( mor_2 ); + + end ); + + ## + AddIsCongruentForMorphisms( C, + function ( C, mor_1, mor_2 ) + + return IsEqualForMorphisms( C, mor_1, mor_2 ); + + end ); + + AddIdentityMorphism( C, + function ( C, obj ) + + return MorphismConstructor( C, + obj, + PairGAP( BigInt( 0 ), + CapJitTypedExpression( [ ], ( ) -> CapJitDataTypeOfListOf( IsBigInt ) ) ), + obj ); + + end ); + + AddPreCompose( C, + function ( C, mor_1, mor_2 ) + + return MorphismConstructor( C, + Source( mor_1 ), + PairGAP( MorphismLength( mor_1 ) + MorphismLength( mor_2 ), + @Concatenation( MorphismIndices( mor_1 ), MorphismIndices( mor_2 ) ) ), + Target( mor_2 ) ); + + end ); + + ## + AddSetOfObjectsOfCategory( C, + function ( C ) + + return List( (1):(NumberOfObjects( UnderlyingQuiver( C ) )), obj_index -> + CreateCapCategoryObjectWithAttributes( C, ObjectIndex, obj_index ) ); + + end ); + + ## + AddSetOfGeneratingMorphismsOfCategory( C, + function ( C ) + local q, s, t; + + q = UnderlyingQuiver( C ); + + s = IndicesOfSources( q ); + t = IndicesOfTargets( q ); + + return List( (1):(NumberOfMorphisms( q )), mor -> + MorphismConstructor( C, + SetOfObjects( C )[s[mor]], + PairGAP( BigInt( 1 ), [ BigInt( mor ) ] ), + SetOfObjects( C )[t[mor]] ) ); + + end ); + + ## + AddRandomObjectByInteger( C, + function ( C, n ) + + return Random( SetOfObjects( C ) ); + + end ); + + ## + AddRandomMorphismWithFixedSourceByInteger( C, + function ( C, obj, n ) + local s, t, m; + + s = ObjectIndex( obj ); + t = Random( (1):(NumberOfObjects( UnderlyingQuiver( C ) )) ); + + m = ExternalHomsWithGivenLength( C, BigInt( 0 ), BigInt( n ) )[s][t]; + + if (m == []) + return IdentityMorphism( C, obj ); + else + return Random( m ); + end; + + end ); + + ## + AddRandomMorphismWithFixedRangeByInteger( C, + function ( C, obj, n ) + local s, t, m; + + s = Random( (1):(NumberOfObjects( UnderlyingQuiver( C ) )) ); + t = ObjectIndex( obj ); + + m = ExternalHomsWithGivenLength( C, BigInt( 0 ), BigInt( n ) )[s][t]; + + if (m == []) + return IdentityMorphism( C, obj ); + else + return Random( m ); + end; + + end ); + + ## + AddRandomMorphismWithFixedSourceAndRangeByInteger( C, + function ( C, obj_1, obj_2, n ) + local s, t, p; + + s = ObjectIndex( obj_1 ); + t = ObjectIndex( obj_2 ); + + p = PositionProperty( (1):(n + 1), i -> ExternalHomsWithGivenLength( C, BigInt( n + 1 - i ) )[s][t] != [] ); + + if (p == fail) + Error( "The Hom-set between the specified source and target objects is empty!\n" ); + else + return Random( ExternalHomsWithGivenLength( C, BigInt( n + 1 - p ) )[s][t] ); + end; + + end ); + + # Homomorphism Structure - Only for path categories with underlying acyclic quivers + + if (IsFinitePathCategory( C ) ) + + SetIsFiniteCategory( C, true ); + + range_cat = range_of_HomStructure; + + if (@not IsSkeletalCategoryOfFiniteSets( range_cat )) + range_cat = SkeletalFinSets; + end; + + SET_RANGE_CATEGORY_Of_HOMOMORPHISM_STRUCTURE( C, range_cat ); + + @Assert( 0, IsIdenticalObj( RangeCategoryOfHomomorphismStructure( C ), range_cat ) ); + + AddMorphismsOfExternalHom( C, + function ( C, obj_1, obj_2 ) + local s, t; + + s = ObjectIndex( obj_1 ); + t = ObjectIndex( obj_2 ); + + return ExternalHoms( C )[s][t]; + + end ); + + else + + SetIsFiniteCategory( C, false ); + + end; + + Finalize( C ); + + return C; + +end ) ); + +## +@InstallMethod( SetOfObjects, + "for a path category", + [ IsPathCategory ], + + function( cat ) + + return SetOfObjectsOfCategory( cat ); + +end ); + +## +@InstallMethod( SetOfGeneratingMorphisms, + "for a path category", + [ IsPathCategory ], + + function( cat ) + + return SetOfGeneratingMorphismsOfCategory( cat ); + +end ); + +## +@InstallMethod( DecompositionIndicesOfMorphism, + "for a path category and a morphism therein", + [ IsPathCategory, IsPathCategoryMorphism ], + + function( C, mor ) + + return -1 + MorphismDatum( C, mor )[2]; + +end ); + +## +@InstallMethod( DecompositionOfMorphismInCategory, + "for a morphism in a path category", + [ IsPathCategoryMorphism ], + + function( mor ) + local C, dec; + + C = CapCategory( mor ); + + dec = SetOfGeneratingMorphisms( C )[1 + DecompositionIndicesOfMorphism( C, mor )]; + + if (ForAny( dec, IsEqualToIdentityMorphism )) + Error( "one of the generating morphisms is an identity morphism\n" ); + end; + + return dec; + +end ); + +## +@InstallMethod( ExternalHomsWithGivenLengthDataOp, + [ IsPathCategory, IsBigInt ], + + function ( C, len ) + local q, nr_objs, nr_gmors, gmors, data, prev_data, r, j, s; + + q = UnderlyingQuiver( C ); + + nr_objs = NumberOfObjects( q ); + nr_gmors = NumberOfMorphisms( q ); + + gmors = List( (1):(nr_gmors), j -> PairGAP( IndicesOfSources( q )[j], IndicesOfTargets( q )[j] ) ); + + data = List( (1):(nr_objs), s -> List( (1):(nr_objs), t -> [ ] ) ); + + if (len == 0) + + for r in (1):(nr_objs) + data[r][r] = @Concatenation( data[r][r], [ [ ] ] ); + end; + + else + + prev_data = ExternalHomsWithGivenLengthData( C, len - 1 ); + + # It is better to get the morphisms already sorted from max to min, hence: + + if (C.admissible_order == "Dp") + + for r in (1):(nr_objs) + for j in (1):(nr_gmors) + data[gmors[j][1]][r] = @Concatenation( data[gmors[j][1]][r], List( prev_data[gmors[j][2]][r], l -> @Concatenation( [ j ], l ) ) ); + end; + end; + + elseif (C.admissible_order == "dp") + + for s in (1):(nr_objs) + for j in (1):(nr_gmors) + data[s][gmors[j][2]] = @Concatenation( data[s][gmors[j][2]], List( prev_data[s][gmors[j][1]], l -> @Concatenation( l, [ j ] ) ) ); + end; + end; + + end; + + end; + + return data; + +end ); + +## +@InstallMethod( ExternalHomsWithGivenLengthOp, + [ IsPathCategory, IsBigInt ], + + function ( C, len ) + local q, supports; + + q = UnderlyingQuiver( C ); + + supports = ExternalHomsWithGivenLengthData( C, len ); + + return List( (1):(NumberOfObjects( q )), s -> + List( (1):(NumberOfObjects( q )), t -> + List( supports[s][t], supp -> + MorphismConstructor( C, + SetOfObjects( C )[s], + PairGAP( len, List( supp, i -> BigInt( i ) ) ), + SetOfObjects( C )[t] ) ) ) ); + +end ); + +## +@InstallMethod( ExternalHomsWithGivenLength, + "for path categories", + [ IsCapCategory, IsBigInt, IsBigInt ], + + function ( C, l, u ) + local nr_objs; + + nr_objs = NumberOfObjects( UnderlyingQuiver( C ) ); + + return LazyHList( (1):(nr_objs), + s -> LazyHList( (1):(nr_objs), + t -> @Concatenation( List( (l):(u), + len -> ExternalHomsWithGivenLength( C, u + l - len )[s][t] ) ) ) ); + +end ); + +## +@InstallMethod( UnderlyingQuiverObject, + [ IsPathCategoryObject ], + + function ( obj ) + local q; + + q = UnderlyingQuiver( CapCategory( obj ) ); + + return SetOfObjects( q )[ObjectIndex( obj )]; + +end ); + +## +@InstallMethod( LaTeXOutput, + [ IsPathCategoryObject ], + + function ( obj ) + + return LaTeXOutput( UnderlyingQuiverObject( obj ) ); + +end ); + +## +@InstallMethod( ObjectLabel, + [ IsPathCategoryObject ], + + function ( obj ) + + return ObjectLabel( UnderlyingQuiverObject( obj ) ); + +end ); + +## +@InstallMethod( CanonicalRepresentative, + [ IsPathCategoryMorphism ], + + IdFunc +); + +## +@InstallMethod( MorphismLabel, + [ IsPathCategoryMorphism ], + + function ( alpha ) + local C, datum, labels; + + C = CapCategory( alpha ); + + if (MorphismLength( alpha ) == 0) + + return @Concatenation( "id(", ObjectLabel( Source( alpha ) ), ")" ); + + else + + labels = CollectEntries( List( MorphismSupport( alpha ), MorphismLabel ) ); + + return JoinStringsWithSeparator( + ListN( labels, + function ( l ) + + if (l[2] == 1) + return l[1]; + else + return @Concatenation( l[1], "^", StringGAP( l[2] ) ); + end; + + end ), "β‹…" ); + + end; + +end ); + +## +@InstallMethod( MorphismSupport, + [ IsPathCategoryMorphism ], + + function ( alpha ) + local q; + + q = UnderlyingQuiver( CapCategory( alpha ) ); + + return SetOfMorphisms( q )[MorphismIndices( alpha )]; + +end ); + +## +@InstallMethod( MorphismConstructor, + [ IsPathCategory, IsPathCategoryObject, IsInt, IsDenseList, IsPathCategoryObject ], + + function ( C, source, length, support, target ) + + #% CAP_JIT_DROP_NEXT_STATEMENT + @Assert( 0, ForAll( support, MorphismFilter( UnderlyingQuiver( C ) ) ) ); + + return MorphismConstructor( C, + source, + PairGAP( length, List( support, MorphismIndex ) ), + target ); + +end ); + +## +@InstallMethod( LaTeXOutput, + [ IsPathCategoryMorphism ], + + function ( alpha ) + local C, datum, string, labels; + + C = CapCategory( alpha ); + + datum = MorphismDatum( alpha ); + + if (datum[1] == 0) + + string = @Concatenation( "id(", LaTeXOutput( Source( alpha ) ), ")" ); + + else + + labels = CollectEntries( LabelsOfMorphisms( UnderlyingQuiver( C ) )[MorphismIndices( alpha )] ); + + string = JoinStringsWithSeparator( + ListN( labels, + function ( label ) + + if (label[2] == 1) + return label[1]; + else + return @Concatenation( label[1], "^[", StringGAP( label[2] ), "]" ); + end; + + end ), " " ); + + end; + + if (ValueOption( "OnlyDatum" ) == true) + + return string; + + else + + return @Concatenation( + "[", LaTeXOutput( Source( alpha ) ), "]-\\left(", + "[", string, "]\\right)\\rightarrow", + "[", LaTeXOutput( Target( alpha ) ), "]" ); + + end; + +end ); + +#= comment for Julia +## +@InstallMethod( AssignSetOfObjects, + [ IsPathCategory, IsString ], + + function ( C, label ) + local names, func; + + names = LabelsOfObjects( UnderlyingQuiver( C ) ); + + if (label == "" && ForAny( names, name -> IntGAP( name ) != fail )) + Error( "the