diff --git a/.github/workflows/docker-testbot.yml b/.github/workflows/docker-testbot.yml new file mode 100644 index 00000000000..8afef32a86f --- /dev/null +++ b/.github/workflows/docker-testbot.yml @@ -0,0 +1,43 @@ +# This workflow builds the Macaulay2 testbot Docker image from +# M2/BUILD/docker/testbot/Dockerfile and pushes it to GitHub Packages, +# tagged with the current Macaulay2 version (see M2/VERSION) and "latest". +# +# The resulting image is published at +# https://github.com/Macaulay2/M2/pkgs/container/testbot + +name: Build and push testbot Docker image + +on: workflow_dispatch + +env: + IMAGE_NAME: ghcr.io/macaulay2/testbot + +jobs: + docker-testbot: + runs-on: ubuntu-latest + permissions: + packages: write + + steps: + - uses: actions/checkout@v6 + + - name: Determine image tags + run: | + M2_VERSION=$(cat M2/VERSION) + echo "M2_VERSION=$M2_VERSION" >> "$GITHUB_ENV" + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + context: M2/BUILD/docker/testbot + push: true + tags: | + ${{ env.IMAGE_NAME }}:v${{ env.M2_VERSION }} + ${{ env.IMAGE_NAME }}:latest diff --git a/.github/workflows/test_build.yml b/.github/workflows/test_build.yml index c767028dbc1..8d743c6f24a 100644 --- a/.github/workflows/test_build.yml +++ b/.github/workflows/test_build.yml @@ -63,6 +63,7 @@ jobs: run: | brew config brew update + brew trust macaulay2/tap brew tap macaulay2/tap brew install automake bison boost libtool tbb ccache ctags llvm make yasm libffi msolve googletest fplll eigen jansson r palp brew install texinfo || true # sometimes post-install step fails diff --git a/M2/Macaulay2/packages/=distributed-packages b/M2/Macaulay2/packages/=distributed-packages index 3e6b396f11e..f582931d62f 100644 --- a/M2/Macaulay2/packages/=distributed-packages +++ b/M2/Macaulay2/packages/=distributed-packages @@ -224,6 +224,7 @@ SpecialFanoFourfolds RationalPoints2 SuperLinearAlgebra SubalgebraBases +Subrings AInfinity LinearTruncations ThinSincereQuivers diff --git a/M2/Macaulay2/packages/SubalgebraBases.m2 b/M2/Macaulay2/packages/SubalgebraBases.m2 index 848efbdea04..4155b666e7d 100644 --- a/M2/Macaulay2/packages/SubalgebraBases.m2 +++ b/M2/Macaulay2/packages/SubalgebraBases.m2 @@ -30,6 +30,7 @@ newPackage( Headline => "Canonical subalgebra bases (aka SAGBI/Khovanskii bases)", AuxiliaryFiles => true, -- set to true if package comes with auxiliary files DebuggingMode => false, -- set to true only during development + PackageExports => {"Subrings"}, Keywords => {"Commutative Algebra"}, Certification => { "journal name" => "Journal of Software for Algebra and Geometry", diff --git a/M2/Macaulay2/packages/SubalgebraBases/classes.m2 b/M2/Macaulay2/packages/SubalgebraBases/classes.m2 index 173d9701428..02d99bab068 100644 --- a/M2/Macaulay2/packages/SubalgebraBases/classes.m2 +++ b/M2/Macaulay2/packages/SubalgebraBases/classes.m2 @@ -8,6 +8,12 @@ -- It also contains in its cache a SAGBIBasis -- object which is the 'furthest-advanced' -- computation data + +-* +------------------------------- +-- Moved to Subrings package -- +------------------------------- + Subring = new Type of HashTable -- Subring constructor @@ -57,6 +63,8 @@ net Subring := S -> ( toString(A) | ", subring of " | toString(R) ) +*- + -- SAGBIBasis computation object data-type that inherits from a HashTable -- A SAGBIBasis represents a partial or complete SAGBI computation. -- It contains all the data necessary to continue a computation diff --git a/M2/Macaulay2/packages/SubalgebraBases/documentation.m2 b/M2/Macaulay2/packages/SubalgebraBases/documentation.m2 index e488a4d6cc4..886b2a03242 100644 --- a/M2/Macaulay2/packages/SubalgebraBases/documentation.m2 +++ b/M2/Macaulay2/packages/SubalgebraBases/documentation.m2 @@ -282,7 +282,7 @@ doc /// on a collection of ring elements against each other, one at a time. This is typically performed on a set of generators of a - @TO "Subring"@ or @TO "SAGBIBasis"@. + @TO "Subrings:Subring"@ or @TO "SAGBIBasis"@. The result of each subduction replaces the original element in the collection and zeros are removed from the collection. If the elements form a subalgebra basis, then the result of @@ -1416,7 +1416,7 @@ doc /// for the intersection but the algorithm cannot guarantee it. - This function can also be run on a sequence containing both @TO "Subring"@ and + This function can also be run on a sequence containing both @TO "Subrings:Subring"@ and @TO "IntersectedSubring"@ types. When @TO "CheckFullIntersection"@ is true, all intermediate intersections are checked for completeness. Example @@ -1441,7 +1441,7 @@ doc /// The type of all subrings arising from intersection Description Text - @TT "IntersectedSubring"@ is a type of @TO "Subring"@ produced + @TT "IntersectedSubring"@ is a type of @TO "Subrings:Subring"@ produced by intersecting two subrings using the function @TO "intersect"@. The function @TO "intersect"@ is the constructor for @TT "IntersectedSubring"@. Applying the function @TO "isFullIntersection"@ to an instance @@ -1568,6 +1568,7 @@ doc /// -- ## classes.m2 documentation ## -- ############################## -- Subring +-* doc /// Key Subring @@ -1575,18 +1576,18 @@ doc /// The type of all subrings Description Text - @TT "Subring"@ is a type that stores information associated + @TT "Subrings:Subring"@ is a type that stores information associated to a subring of a polynomial ring or quotient ring, such as a set of subring generators and a reference to the ring containing these generators. - An instance of a @TT "Subring"@ is constructed with the function @TO "subring"@. - For many uses, it is suggested to use a @ TT "Subring"@, + An instance of a @TT "Subrings:Subring"@ is constructed with the function @TO "subring"@. + For many uses, it is suggested to use a @ TT "Subrings:Subring"@, as the computation objects (@TO "SAGBIBasis"@) are handled behind the scenes, and the user experience is more streamlined. - Every instance of @TT "Subring"@ has the following keys + Every instance of @TT "Subrings:Subring"@ has the following keys (some of which are strings): @UL { @@ -1629,9 +1630,9 @@ doc /// A = subring S Inputs M:Matrix - whose entries are the generators for the constructed @TO "Subring"@. + whose entries are the generators for the constructed @TO "Subrings:Subring"@. L:List - containing generators for the constructed @TO "Subring"@. + containing generators for the constructed @TO "Subrings:Subring"@. S:SAGBIBasis GeneratorSymbol=>Symbol a symbol to be used for the variables of the @ TT "presentationRing" @. @@ -1640,7 +1641,7 @@ doc /// generated by the input generators. Description Text - This function serves as the canonical constructor for the @TO "Subring"@ type. + This function serves as the canonical constructor for the @TO "Subrings:Subring"@ type. For many uses, it is suggested to use @ ofClass Subring@, as the computation objects (@TO "SAGBIBasis"@) are handled behind the scenes, and @@ -1677,7 +1678,7 @@ doc /// result:Matrix Description Text - Returns a generating set for the @TO "Subring"@ as a one-row matrix. + Returns a generating set for the @TO "Subrings:Subring"@ as a one-row matrix. Example R = QQ[x,y,z]; S = subring({x^2, y^2, z^2}); @@ -1701,7 +1702,7 @@ doc /// result:Ring Description Text - Returns the ambient ring of the generating set of the @TO "Subring"@. + Returns the ambient ring of the generating set of the @TO "Subrings:Subring"@. This may be a @TO "PolynomialRing"@ or @TO "QuotientRing"@. Example R = QQ[x,y,z]; @@ -1731,7 +1732,7 @@ doc /// the number of generators of S Description Text - Returns the number of generators of a @TO "Subring"@. + Returns the number of generators of a @TO "Subrings:Subring"@. Example R = QQ[x,y,z]; S = subring({x^2, y^2, z^2, x^2+y^2}); @@ -1745,6 +1746,7 @@ doc /// (net, Subring) (flattenedRing, Subring) /// +*- -- (numgens, SAGBIBasis) doc /// Key @@ -1777,6 +1779,7 @@ doc /// (net, Subring) (flattenedRing, SAGBIBasis) /// +-* -- (net, Subring) doc /// Key @@ -1792,7 +1795,7 @@ doc /// obtained by formatting S for printing. Description Text - Displays the presentation and ambient rings of a @TO "Subring"@. + Displays the presentation and ambient rings of a @TO "Subrings:Subring"@. Example R = QQ[x,y]; S = subring{x^2,x*y^2,y^4} @@ -1827,6 +1830,7 @@ doc /// subring presentationRing /// +*- -- SAGBIBasis doc /// Key @@ -1909,7 +1913,7 @@ doc /// Text This function serves as the canonical constructor for the @TO "SAGBIBasis"@ type. The @TT "SAGBIBasis"@ type is also the output of the function @TO "sagbi"@. - The @ TO "Subring"@ used to construct a @TT "SAGBIBasis"@ may be recovered using + The @ TO "Subrings:Subring"@ used to construct a @TT "SAGBIBasis"@ may be recovered using @TO "subring"@ Example R = QQ[x,y]; @@ -1951,7 +1955,7 @@ doc /// Description Text Returns a list of subalgebra generators of the - @TO "Subring"@ underlying the @TO "SAGBIBasis"@. + @TO "Subrings:Subring"@ underlying the @TO "SAGBIBasis"@. If the subalgebra generators do not form a complete subalgebra basis (for example if they were obtained from a partial computation), then the generators obtained from this command @@ -2015,7 +2019,7 @@ doc /// Description Text Returns the ambient ring of @ ofClass SAGBIBasis @. - This is the ambient ring of the generating @TO "Subring"@ + This is the ambient ring of the generating @TO "Subrings:Subring"@ This may be a @TO "PolynomialRing"@ or @TO "QuotientRing"@. Example R = QQ[x,y,z]; @@ -2030,7 +2034,6 @@ doc /// SAGBIBasis sagbiBasis (gens, SAGBIBasis) - (ambient, Subring) /// -- (ring, SAGBIBasis) doc /// @@ -2420,6 +2423,7 @@ doc /// UseSubringGens SubductionMethod /// +-* -- presentationRing doc /// Key @@ -2471,6 +2475,7 @@ doc /// (ambient, Subring) (flattenedRing, Subring) /// +*- -- ######################################### -- ## Short Explanation of Screws Example ## -- ######################################### @@ -2634,6 +2639,7 @@ doc /// subalgebraBasis subduction /// +-* -- flatenedRing doc /// Key @@ -2643,8 +2649,8 @@ doc /// Headline The flattened ring of a subring or sagbiBasis Usage - result = flattened S - result = flattened SB + result = flattenedRing S + result = flattenedRing SB Inputs S:Subring SB:SAGBIBasis @@ -2667,4 +2673,5 @@ doc /// sagbiBasis (ambient, SAGBIBasis) /// +*- end -- diff --git a/M2/Macaulay2/packages/SubalgebraBases/exports.m2 b/M2/Macaulay2/packages/SubalgebraBases/exports.m2 index a6af4f4fe5c..57f3dd4ac55 100644 --- a/M2/Macaulay2/packages/SubalgebraBases/exports.m2 +++ b/M2/Macaulay2/packages/SubalgebraBases/exports.m2 @@ -16,17 +16,17 @@ export { -- From classes.m2 export { - "Subring", + -- "Subring", "SAGBIBasis", - "subring", + -- "subring", "Compute", "sagbiBasis", - "GeneratorSymbol", - "presentationRing", + -- "GeneratorSymbol", + -- "presentationRing", "sagbiStatus", "sagbiLimit", "sagbiDegree", - "flattenedRing" + -- "flattenedRing" } -- From sagbi-functions.m2 diff --git a/M2/Macaulay2/packages/SubalgebraBases/sagbi-functions.m2 b/M2/Macaulay2/packages/SubalgebraBases/sagbi-functions.m2 index 0d04ac2d54f..9a1b370fc1c 100644 --- a/M2/Macaulay2/packages/SubalgebraBases/sagbi-functions.m2 +++ b/M2/Macaulay2/packages/SubalgebraBases/sagbi-functions.m2 @@ -566,6 +566,7 @@ subringIntersection(Subring, Subring) := IntersectedSubring => opts -> (S1, S2) "ambientRing" => A, "flattenedRing" => Q, "generators" => intersectionGens, + "originalGenerators" => S1#"inverseFlatteningMap" intersectionGens, "presentationRing" => subductionRing, "presentationMap" => presentationMap, cache => new CacheTable from {}, diff --git a/M2/Macaulay2/packages/Subrings.m2 b/M2/Macaulay2/packages/Subrings.m2 new file mode 100644 index 00000000000..fd6501c9583 --- /dev/null +++ b/M2/Macaulay2/packages/Subrings.m2 @@ -0,0 +1,218 @@ +-- -*- coding: utf-8 -*- +newPackage( + "Subrings", + Version => "1.1", + Date => "July 3, 2026", + Authors => { + {Name => "Francesca Gandini", Email => "fra.gandi.phd@gmail.com"}, + {Name => "Casey Hill", Email => "casey.hill@uky.edu"}, + {Name => "Trevor K. Karn", Email => "karnx018@umn.edu"}, + {Name => "Miranda Moore", Email => "moor2340@umn.edu"}, + {Name => "Christopher O'Neill", Email => "cdoneill@sdsu.edu"}, + {Name => "Oliver Clarke", Email => "oliver.clarke@durham.ac.uk"} + }, + Headline => "subrings of polynomial rings and quotients", + Keywords => {"Commutative Algebra"}, + AuxiliaryFiles => true, + ) + + +export {"subring", + "subringGenerators", + "presentationRing", + "presentationMap", + "presentationIdeal", + "toQuotientRing", + "isSubringElement", + "GeneratorSymbol", + "flattenedRing", + "Subring", + } + +Subring = new Type of HashTable + +-- a method to create subrings from a `Matrix` of generators +subring = method( + Options => {GeneratorSymbol=>null} + ) +subring Matrix := opts -> genMatrix -> ( + if genMatrix.cache#?Subring then return genMatrix.cache#Subring; + -- compute presentation ring + R := ring genMatrix; + -- deal with towers of rings + (F,RtoF,FtoR) := flattenRing(R,Result=>3); + coeffRing := coefficientRing F; + local subductionRing; + if instance(opts.GeneratorSymbol,Nothing) then + subductionRing = coeffRing(monoid[Variables => numcols genMatrix]) + else if instance(opts.GeneratorSymbol,Symbol) then + subductionRing = coeffRing[opts.GeneratorSymbol_1..opts.GeneratorSymbol_(numcols genMatrix)] + else error("Invalid GeneratorSymbol option"); + presentationMap := map(R,subductionRing,genMatrix); + S := new Subring from { + "ambientRing" => R, + "flattenedRing" => F, + "generators" => RtoF genMatrix, + "originalGenerators" => genMatrix, + "presentationRing" => subductionRing, + "presentationMap" => presentationMap, + "flatteningMap" => RtoF, + "inverseFlatteningMap" => FtoR, + cache => new CacheTable from {} + }; + genMatrix.cache#Subring = S + ) + +-- a method to create subrings from a `List` of generators +subring List := opts -> genList -> ( + subring(matrix {genList}, opts) + ) + +flattenedRing = method() +flattenedRing Subring := S -> S#"flattenedRing" + +flattenRing Subring := opts -> S -> S#"flattenedRing" + +presentationRing = method() +presentationRing Subring := S -> ( + S#"presentationRing" + ) + +presentationMap = method() +presentationMap Subring := S -> ( + S#"presentationMap" + ) + +presentationIdeal = method() +presentationIdeal Subring := S -> ( + f := presentationMap S; + return ker f; --kernel is cached automatically + ) + +-- a quotient ring isomorphic to the image of the subring inside of the presentation ring +toQuotientRing = method() +toQuotientRing Subring := S -> ( + P := presentationRing S; + I := presentationIdeal S; + return P/I; + ) + +subringGenerators = method() -- gens that live in flattened ring +subringGenerators Subring := S -> S#"generators" + +generators Subring := Matrix => opts -> S -> ( -- gens that live in ambient ring + S#"originalGenerators" + ) + +ambient Subring := S -> S#"ambientRing" + +numgens Subring := S -> numcols gens S + +-- format printing of Subring type +net Subring := S -> ( + R := ambient S; + P := presentationRing S; + g := flatten entries gens S; + genstr := ""; + if #g <= 3 then ( + genstr = toString(g_{0 .. min(2, #g-1)}); + ) else ( + genstr = "{" | toString(g_0) | ", " | toString(g_1) | ", " | toString(g_2) | ", ...}"; + ); + + "Subring of " | toString(R) | " generated by " | genstr | " with presentation ring " | toString(P) + ) + + +-- given a subring S and an element x of the ambient ring, checks whether x is in S +isSubringElementInternal = method() +isSubringElementInternal(RingElement, Subring) := (r, S) -> ( + if not S.cache#?"tensorGraphIdeal" and not S.cache#?"ambientToTensor" then ( + R := ambient S; + F := flattenRing S; + P := presentationRing S; + T := tensor(F, P, MonomialOrder=>Eliminate(numgens F)); + gT := vars T; + F2T := map(T, F, gT_{0 .. numgens F - 1}); + R2T := F2T * (S#"flatteningMap"); + P2T := map(T, P, gT_{numgens F .. numgens T - 1}); + subringGens := subringGenerators S; + presGens := matrix {gens P}; + graphIdealGens := P2T(presGens) - F2T(subringGens); + I := ideal graphIdealGens; + S.cache#"tensorGraphIdeal"=I; + S.cache#"ambientToTensor"=R2T; + ); + M := matrix {{S.cache#"ambientToTensor"(r) % S.cache#"tensorGraphIdeal"}}; + selectInSubring(1, M) == M + ) + +-- use hooks to select how 'isSubringElement' runs: +-- by default 'isSubringElement' uses the internal method above +-- other hooks may be added by other packages: +-- +-- >> addHook((isSubringElement, RingElement, Subring), newMethod, Strategy => "name of strategy") +-- +-- where 'newMethod(RingElement, Subring) := ...' should return 'null' +-- if the new strategy does not apply +-- new hooks should be added in order from least specific to most specific +isSubringElement = method( + Options => true + ) + +addHook((isSubringElement, RingElement, Subring), isSubringElementInternal, Strategy => "default") + +isSubringElement(RingElement, Subring) := true >> opts -> args -> runHooks((isSubringElement, RingElement, Subring), args, opts); + + + +-- equality of Subrings +-- check that every generator of S1 is in S2 and every generator of S2 is in S1 +Subring == Subring := (S1, S2) -> ( + if not (ambient S1) === (ambient S2) then return false; + all(entries(subringGenerators S1)_0, f -> isSubringElement(f, S2)) and all(entries(subringGenerators S2)_0, f -> isSubringElement(f, S1)) + ) + + +----------------------------------------- +--- Load documentation and test files --- +----------------------------------------- +beginDocumentation() + +load "./Subrings/SubringDoc.m2" +load "./Subrings/SubringTests.m2" + +end-- + +uninstallPackage "Subrings" +restart +installPackage "Subrings" +needsPackage "TestAudit" +testAudit("Subrings", ScoreReport => true) + +R = QQ[x] +S1 = subring {x, x^2} +S2 = subring {x^2} +S3 = subring {x} +S1 == S3 --true +S1 == S2 --false + +net S3 + +mingens S1 +presentationRing S1 +mingens + +gens S1 + +-- run tests +check Subrings + + + +R = QQ[x][y] +S = subring {x+y, x*y} +r = x^4 + y^4 +isSubringElement(r, S) +isSubringElement(r + x, S) +isSubringElement(r + x*y, S) diff --git a/M2/Macaulay2/packages/Subrings/SubringDoc.m2 b/M2/Macaulay2/packages/Subrings/SubringDoc.m2 new file mode 100644 index 00000000000..200282fe5d2 --- /dev/null +++ b/M2/Macaulay2/packages/Subrings/SubringDoc.m2 @@ -0,0 +1,449 @@ +-* + + Copyright 2023, Oliver Clarke, Francesca Gandini, + Casey Hill, Trevor Karn, Miranda Moore, Chris O'Neill + + You may redistribute this file under the terms of the GNU General Public + License as published by the Free Software Foundation, either version 2 of + the License, or any later version. +*- + + +beginDocumentation() + +doc /// + Node + Key + Subrings + Headline + a package to deal with subrings + Description + Text + {\em Subrings} is a package to give basic subroutines for subrings. + Example + needsPackage("Subrings") + Text + In particular, this package allows one to do computations in a subring + and pass back and forth between the ambient ring and the subring. + It also allows one to check if two subrings are secretly the same. + Caveat + There are other subring flavor things out there. + For example, the @TO "SubalgebraBases::SubalgebraBases"@ package contains a subring. + That subring will eventually be deprecated in favor of this one. + Subnodes + Subring + subring + presentationIdeal + presentationRing + presentationMap + isSubringElement + toQuotientRing + subringGenerators + (symbol ==, Subring, Subring) + (ambient, Subring) + (net, Subring) +/// + +doc /// + Key + Subring + Headline + the class of finitely generated subrings of polynomial rings + Description + Text + To see how to specify a subring, see @TO subring @. + A subring of @ ofClass{PolynomialRing} @ is a ring with unity + contained inside of another ambient ring that is closed + under the operations of the ambient ring. + + The user can specify either @ ofClass{List} @ or @ ofClass{Matrix} @ + whose entries are the generators. + Example + R = QQ[x,y]; + L = {x^2, y^2}; + S = subring L + M = matrix({{x^2, y^2}}) + S = subring M + SeeAlso + subring +/// + + +doc /// + Key + subring + (subring, Matrix) + (subring, List) + [subring, GeneratorSymbol] + Headline + Construct a subring of a polynomial ring + Usage + S = subring M + S = subring L + Inputs + M:Matrix + of generators for a subring of a @ ofClass{PolynomialRing} @ + L:List + of generators for a subring of a @ ofClass{PolynomialRing} @ + GeneratorSymbol=>Symbol + a symbol to be used for the variables of the @ TT "presentationRing" @. + Outputs + S:Subring + the subring of the polynomial ring + Description + Text + An easy way to specify a subring is to specify the ambient ring and the generators of a desired subring as a matrix. The ambient ring is implicit in the constructor function. + Example + R = QQ[x,y] + M = matrix(R, {{x^2, x*y, y^2}}) + S = subring M + Text + This function also accepts a list of elements of a polynomial ring as an input. + Example + R = QQ[x,y] + L = {x^2, x*y, y^2} + S = subring L + SeeAlso + Subring + (gens, Subring) + (ambient, Subring) + (numgens, Subring) + (net, Subring) + presentationIdeal + presentationRing +/// + + +doc /// + Key + presentationIdeal + (presentationIdeal, Subring) + Headline + Compute the presentation ideal of a subring + Usage + I = presentationIdeal S + Inputs + S:Subring + Outputs + I:Ideal + the presentation ideal of the subring + Description + Text + This function finds the presentation ideal of the subring, which is defined to + be the presentation ring modulo the presentation map. + Example + R = QQ[x,y] + S = subring {x^2, x*y, y^2} + I = presentationIdeal S + SeeAlso + Subring + subring + +/// + +doc /// + Key + presentationRing + (presentationRing, Subring) + Headline + a polynomial ring with a variable for each subring generator + Usage + P = presentationRing S + Inputs + S:Subring + Outputs + P:PolynomialRing + a polynomial ring with one variable for each generator of the subring + Description + Text + The {\tt presentationRing} of a subring {\tt S} is a polynomial ring + with a variable for each generator of {\tt S}. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g; + numgens presentationRing S + Text + This should not be confused with @TO toQuotientRing @, + which yields a quotient of the presentation ring. In this example, + even though there is an algebraic relation + between the three generators, the presentation ring doesn't know + that. + Example + P = presentationRing S; + P_0*P_2 - P_1^2 + SeeAlso + Subring + subring +/// + +doc /// + Key + presentationMap + (presentationMap, Subring) + Headline + the map from the presentation ring into a subring + Usage + f = presentationMap S + Inputs + S:Subring + Outputs + f:RingMap + the map sending polynomial ring generators to subring generators + Description + Text + There exists a map sending each generator of the presentation ring to + the corresponding element of the ambient ring. This is that map. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g; + f = presentationMap S + P = presentationRing S + p = P_0 * P_2 - P_1^2 + f(p) + SeeAlso + Subring + subring + +/// + +doc /// + Key + isSubringElement + (isSubringElement, RingElement, Subring) + Headline + query if an element of ambient ring is in the subring + Usage + isSubringElement(x, S) + Inputs + x:RingElement + an element of the ambient ring + S:Subring + the subring which may or may not contain x + Description + Text + This determines if an element is in the subring. + In the first example, it is. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g; + isSubringElement(x^2 + x*y, S) + Text + In this example the element is not in the subring. + Example + isSubringElement(x, S) + SeeAlso + Subring + subring + +/// + +doc /// + Key + toQuotientRing + (toQuotientRing, Subring) + Headline + create a quotient ring isomorphic to the subring + Usage + Q = toQuotientRing S + Inputs + S:Subring + Outputs + Q:PolynomialRing + isomorphic to the subring + Description + Text + The subring is isomorphic to a quotient of a polynomial ring + with a variable corresponding to each generator. This + function returns such a quotient ring. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g; + toQuotientRing(S) + Text + This should not be confused with @TO presentationRing@, + which gives only the ambient ring of {\tt Q}. + SeeAlso + Subring + subring + +/// + +doc /// + Key + subringGenerators + (subringGenerators, Subring) + (generators, Subring) + Headline + return the matrix of generators for the subring + Usage + M = subringGenerators S + M = generators S + M = gens S + Inputs + S:Subring + Outputs + M:Matrix + containing the generators of {\tt S}. + Description + Text + The subring is generated by elements of the ambient ring. This function + returns a matrix (over the ambient ring) of these generators. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g; + toQuotientRing(S) + Text + The generators are as given by the user. In particular, they may not + be a minimal generating set if the generating set used to specify + the ring is itself nonminimal. + Example + R = QQ[x,y]; + g = {x, x*y, y, y^2}; + S = subring g; + subringGenerators(S) + Text + This method is also accessible through the generators method, + and thus through the shortened gens method. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g; + generators S + gens S + SeeAlso + Subring + subring + +/// + +doc /// + Key + (symbol ==, Subring, Subring) + Headline + check equality of subrings + Usage + S1 == S2 + Description + Text + Two different subrings may be equal despite being specified by + different generating sets. This binary operator provides a way + to check whether or not two subrings are the same by checking + containments. + Example + R = QQ[x,y]; + g1 = {x^2, x*y, y^2}; + S1 = subring g1 + g2 = {x^2, x*y, y^2, x^2*y^2}; + S2 = subring g2 + S1 == S2 + Text + The ambient ring must be literally the same for two + subrings to be considered the same. + Example + R1 = QQ[x,y]; + g1 = {x^2, y^2}; + R2 = QQ[x,y]; + g2 = {x^2, y^2}; + R1 === R2 + subring(g1) == subring(g2) + Text + Things could also go wrong if the ambient rings have different + numbers of generators. + Example + R3 = QQ[x,y,z]; + g3 = {x^2, y^2}; + subring(g1) == subring(g3) + subring(g2) == subring(g3) + SeeAlso + Subring + subring + +/// + +doc /// + Key + (ambient, Subring) + Headline + get the ambient ring + Usage + R = ambient S + Inputs + S:Subring + Outputs + R:PolynomialRing + of which {\tt S} is understood to be a subset + Description + Text + A subring is by definition a subset of another ring. + This method returns that other ring. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g + R === ambient S + SeeAlso + Subring + subring + +/// + +doc /// + Key + (net, Subring) + Headline + format for printing the subring + Usage + m = net S + Inputs + S:Subring + Outputs + m:Net + a succinct description of S + Description + Text + This provides the expression for printing a `Subring`. + Example + R = QQ[x,y]; + g = {x^2, x*y, y^2}; + S = subring g + SeeAlso + Subring + subring + +/// + +-- flatenedRing +doc /// + Key + flattenedRing + (flattenedRing, Subring) + (flattenRing, Subring) + Headline + The flattened ring of a subring + Usage + result = flattenedRing S + Inputs + S:Subring + Outputs + result:Ring + the flattened ring of the ambient ring + Description + Text + Returns the flattened ring of the ambient ring. + This may be a @TO "PolynomialRing"@ or @TO "QuotientRing"@. + Example + R = (QQ[x])[y]/ideal(x^2-y^3); + S = subring {x+y,x*y}; + ambient S + flattenedRing S + SeeAlso + Subring + subring + (ambient, Subring) + +/// diff --git a/M2/Macaulay2/packages/Subrings/SubringTests.m2 b/M2/Macaulay2/packages/Subrings/SubringTests.m2 new file mode 100644 index 00000000000..492c0bd9038 --- /dev/null +++ b/M2/Macaulay2/packages/Subrings/SubringTests.m2 @@ -0,0 +1,61 @@ +TEST /// + R := QQ[x,y]; + S := subring {x^2, x*y, y^2}; + assert(isSubringElement(x^2, S)); + assert(not isSubringElement(x, S)); +/// + +TEST /// + R := QQ[x,y]; + S1 := subring {x^2, y^2}; + S2 := subring {x^2, x^4, y^2}; + assert(S1 == S2); +/// + +TEST /// + R1 := QQ[x,y]; + S1 := subring {x^2, x*y, y^2}; + R2 := QQ[x,y,z]; + S2 := subring {x^2, x*y, y^2}; + assert(not S1 == S2); +/// + +TEST /// + R := QQ[x,y]; + S := subring {x^2, x*y, y^2}; + assert(class(presentationRing S) === PolynomialRing); + assert(numgens(presentationRing S) == 3); +/// + +TEST /// + R := QQ[x,y]; + S := subring {x^2, x*y, y^2}; + f := presentationMap S; + assert(class(f) === RingMap); + assert(target f === R); + assert(numgens source f == 3); + assert(ambient S === R); + assert(numgens presentationIdeal S == 1); + assert(ring subringGenerators S === R); + assert(instance(toQuotientRing S, QuotientRing)); +/// + + +TEST /// -- check towers of polynomial rings + R := QQ[x][y]; + S := subring {x+y, x*y}; + assert(isSubringElement(x^3+y^3, S)); + assert(not isSubringElement(x^3+y^3+x, S)); + assert(numgens flattenedRing S == 2); + assert(ring subringGenerators S === flattenedRing S); + assert(zero presentationIdeal S); + assert(instance(toQuotientRing S, PolynomialRing)); + assert(ring gens S === R); +/// + +TEST /// -- assignment of GeneratorSymbol in subring + R := QQ[x,y]; + S := subring({x^2, x*y, y^2}, GeneratorSymbol => getSymbol "z"); + u := (presentationRing S)_0; + assert((baseName u)#0 === getSymbol "z"); +///