GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
############################################################################# ## ## HAPPRIME - polynomials.gi ## Functions, Operations and Methods to extend GAP's polynomials ## Paul Smith ## ## Copyright (C) 2008 ## Paul Smith ## National University of Ireland Galway ## ## This file is part of HAPprime. ## ## HAPprime 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. ## ## HAPprime 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, see <http://www.gnu.org/licenses/>. ## ## $Id: polynomials.gi 332 2008-10-10 14:27:21Z pas $ ## ############################################################################# ##################################################################### ## <#GAPDoc Label="TermsOfPolynomial_manPolynomial"> ## <ManSection> ## <Attr Name="TermsOfPolynomial" Arg="poly"/> ## ## <Returns> ## List of pairs ## </Returns> ## <Description> ## Returns a list of the terms in the polynomial. ## This list is a list of pairs of the form <C>[mon, coeff]</C> where ## <C>mon</C> is a monomial and <C>coeff</C> is the coefficient of that ## monomial in the polynomial. The monomials are sorted according to ## the total degree/lexicographic order (the same as the in ## <Ref Oper="MonomialGrLexOrdering" BookName="ref"/>). ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallMethod(TermsOfPolynomial, [IsPolynomial], function(poly) local terms, extrep, fam, one, i, term, mon, coeff; terms := []; extrep := ExtRepPolynomialRatFun(poly); if IsEmpty(extrep) then return []; fi; fam := FamilyObj(poly); i := 1; repeat mon := extrep[i]; coeff := extrep[i+1]; term := [PolynomialByExtRep(fam, [mon, One(coeff)]), coeff]; Add(terms, term); i := i + 2; until i > Length(extrep); return terms; end ); ##################################################################### ##################################################################### ## <#GAPDoc Label="IsMonomial_manPolynomial"> ## <ManSection> ## <Attr Name="IsMonomial" Arg="poly" Label="for polynomial"/> ## ## <Returns> ## Boolean ## </Returns> ## <Description> ## Returns <K>true</K> if <A>poly</A> is a monomial, i.e. the polynomial ## contains only one term. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallMethod(IsMonomial, "for polynomial", [IsPolynomial], function(poly) return Length(ExtRepPolynomialRatFun(poly)) = 2; end ); ##################################################################### ##################################################################### ## <#GAPDoc Label="UnivariateMonomialsOfMonomial_manPolynomial"> ## <ManSection> ## <Attr Name="UnivariateMonomialsOfMonomial" Arg="mon"/> ## ## <Returns> ## List ## </Returns> ## <Description> ## Returns a list of the univariate monomials of the largest order ## whose product equals <A>mon</A>. ## The univariate monomials are sorted according to ## their indeterminate number. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallMethod(UnivariateMonomialsOfMonomial, [IsPolynomial], function(poly) local extrep, fam, coeffring, one, mon, i, unimons; if IsOne(poly) or IsZero(poly) then return [poly]; fi; extrep := ExtRepPolynomialRatFun(poly); fam := FamilyObj(poly); coeffring := Ring(extrep[2]); one := One(coeffring); if Length(extrep) > 2 or extrep[2] <> one then Error("<mon> must be a monomial"); fi; mon := extrep[1]; i := 1; unimons := []; repeat Add(unimons, PolynomialByExtRep(fam, [[mon[i], mon[i+1]], one])); i := i + 2; until i > Length(mon); return unimons; end ); ##################################################################### ##################################################################### ## <#GAPDoc Label="IndeterminateAndExponentOfUnivariateMonomial_manPolynomial"> ## <ManSection> ## <Attr Name="IndeterminateAndExponentOfUnivariateMonomial" Arg="mon"/> ## ## <Returns> ## List ## </Returns> ## <Description> ## Returns a list <C>[indet, exp]</C> where <C>indet</C> is the indeterminate ## of the univariate monomial <A>mon</A> and <C>exp</C> is the exponent ## of that indeterminate in the monomial. If <A>mon</A> is an element in the ## coefficient ring (i.e. the monomial contains no indeterminates) then the ## first element will be <A>mon</A> with an exponent of zero. ## If <A>mon</A> is not a univariate monomial, then <K>fail</K> is returned. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallMethod(IndeterminateAndExponentOfUnivariateMonomial, [IsPolynomial], function(poly) local extrep, one, fam; extrep := ExtRepPolynomialRatFun(poly); if IsEmpty(extrep[1]) then return [extrep[2], 0]; fi; if Length(extrep) <> 2 then return fail; fi; one := One(extrep[2]); fam := FamilyObj(poly); return [PolynomialByExtRep(fam, [[extrep[1][1], 1], one]), extrep[1][2]]; end ); ##################################################################### ##################################################################### ## <#GAPDoc Label="IndeterminatesOfPolynomial_manPolynomial"> ## <ManSection> ## <Attr Name="IndeterminatesOfPolynomial" Arg="poly"/> ## ## <Returns> ## List ## </Returns> ## <Description> ## Returns a list of the indeterminates used in the polynomial <A>poly</A>. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallMethod(IndeterminatesOfPolynomial, [IsPolynomial], function(poly) # Is it a constant? if IsEmpty(ExtRepPolynomialRatFun(poly)) or IsEmpty(ExtRepPolynomialRatFun(poly)[1]) then return []; else return IndeterminatesOfPolynomialRing(DefaultRing(poly)); fi; end ); ##################################################################### ##################################################################### ## <#GAPDoc Label="ReduceIdeal_manPolynomial"> ## <ManSection> ## <Heading>ReduceIdeal</Heading> ## <Oper Name="ReduceIdeal" Arg="I, O" Label="for Ideal"/> ## <Oper Name="ReduceIdeal" Arg="rels, O" Label="for list of relations"/> ## ## <Returns> ## Ideal or list ## </Returns> ## <Description> ## For an ideal <A>I</A> returns an ideal containing a reduced generating set ## for the ideal, i.e. one in which no monomial in a relation in <A>I</A> is ## divisible by the leading term of another polynomial in <A>I</A>. ## The monomial ordering to be used is ## specified by <A>O</A> (see <Ref Sect="Monomial Orderings" BookName="ref"/>). ## The ideal can instead be specified by a list of relations <A>rels</A>, ## in which case a reduced list of relations is returned. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallOtherMethod(ReduceIdeal, "for empty ideal", [IsEmpty, IsMonomialOrdering], function(ideal, order) return []; end ); ##################################################################### InstallOtherMethod(ReduceIdeal, "for Ideal", [IsPolynomialRingIdeal, IsMonomialOrdering], function(ideal, order) return Ideal( LeftActingRingOfIdeal(ideal), ReduceIdeal(GeneratorsOfIdeal(ideal), order)); end ); ##################################################################### InstallMethod(ReduceIdeal, "for list of relations", [IsHomogeneousList and IsRationalFunctionCollection, IsMonomialOrdering], function(I, order) local ideal, i, len, changed, poly; ideal := ShallowCopy(I); len := Length(ideal); repeat i := 1; changed := false; while i <= len do poly := PolynomialReducedRemainder( ideal[i], ideal{Difference([1..len],[i])}, order); if poly <> ideal[i] then changed := true; fi; if IsZero(poly) then ideal[i] := ideal[len]; Unbind(ideal[len]); len := len - 1; else ideal[i] := poly; i := i + 1; fi; od; until not changed; for i in [1..Length(ideal)] do ideal[i] := ideal[i] / LeadingCoefficientOfPolynomial(ideal[i], order); od; return ideal; end ); ##################################################################### ##################################################################### ## <#GAPDoc Label="ReducedPolynomialRingPresentation_manPolynomial"> ## <ManSection> ## <Oper Name="ReducedPolynomialRingPresentation" Arg="R, I[, avoid]"/> ## <Oper Name="ReducedPolynomialRingPresentationMap" Arg="R, I[, avoid]"/> ## ## <Returns> ## List ## </Returns> ## <Description> ## For a polynomial ring <A>R</A> and a list of relations <A>I</A> in that ## ring, returns a list <C>[S, J]</C> representing a polynomial quotient ring ## <M>S/J</M> which is isomorphic to the ring <M>R/I</M>, but which involves ## the minimal number of ring indeterminates. The indeterminates in <C>S</C> ## will be distinct from thise in <A>R</A>, and an optional argument ## <A>avoid</A> can be used to give a list of further indeterminates to avoid ## when creating the ring <C>S</C>. ## <P/> ## The extended version of this function, ## <Ref Oper="ReducedPolynomialRingPresentationMap"/>, returns an additional ## third element to the list, which contains two lists giving the mapping ## between the new ring indeterminates and the old ring indeterminates. The ## first list is of polynomials in the original indeterminates, the ## second the equivalent polynomials in the new ring indeterminates. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallMethod(ReducedPolynomialRingPresentation, "with nothing to avoid", [IsPolynomialRing, IsHomogeneousList and IsRationalFunctionCollection, IsHomogeneousList], function(ring, I, avoid) return ReducedPolynomialRingPresentationMap(ring, I, avoid){[1..2]}; end ); ##################################################################### InstallOtherMethod(ReducedPolynomialRingPresentation, "with nothing to avoid", [IsPolynomialRing, IsHomogeneousList and IsRationalFunctionCollection], function(ring, I) return ReducedPolynomialRingPresentationMap(ring, I, []){[1..2]}; end ); ##################################################################### InstallOtherMethod(ReducedPolynomialRingPresentation, "for empty relations", [IsPolynomialRing, IsEmpty, IsHomogeneousList], function(ring, I, avoid) local newring, newrelations, map; # Just copy the ring newring := PolynomialRing( CoefficientsRing(ring), Length(IndeterminatesOfPolynomialRing(ring)), Concatenation(avoid, IndeterminatesOfPolynomialRing(ring))); newrelations := HAPPRIME_SwitchPolynomialIndeterminates( ring, newring, I); return [newring, newrelations ]; end ); ##################################################################### InstallOtherMethod(ReducedPolynomialRingPresentationMap, "with nothing to avoid", [IsPolynomialRing, IsHomogeneousList and IsRationalFunctionCollection], function(ring, I) return ReducedPolynomialRingPresentationMap(ring, I, []); end ); ##################################################################### InstallOtherMethod(ReducedPolynomialRingPresentationMap, "for empty relations and nothing to avoid", [IsPolynomialRing, IsEmpty], function(ring, I) return ReducedPolynomialRingPresentationMap(ring, I, []); end ); ##################################################################### InstallOtherMethod(ReducedPolynomialRingPresentationMap, "for empty relations", [IsPolynomialRing, IsEmpty, IsHomogeneousList], function(ring, I, avoid) local newring, newrelations, map; # Just copy the ring newring := PolynomialRing( CoefficientsRing(ring), Length(IndeterminatesOfPolynomialRing(ring)), Concatenation(avoid, IndeterminatesOfPolynomialRing(ring))); newrelations := HAPPRIME_SwitchPolynomialIndeterminates( ring, newring, I); return [newring, newrelations, [IndeterminatesOfPolynomialRing(ring), IndeterminatesOfPolynomialRing(newring)] ]; end ); ##################################################################### InstallMethod(ReducedPolynomialRingPresentationMap, [IsPolynomialRing, IsHomogeneousList and IsRationalFunctionCollection, IsHomogeneousList], function(ring, I, avoid) local ideal, indetorder, order, indet, i, t, t2, indets, allindets, ord, removedindets, removedrelations, removedring, unimons, relation, poly, len, nomod, newring, newrelations, map; # Check for unit in the ideal - if so, we return a trivial ring if Length(I) = 1 and IsOne(I[1]) then return [Ring(Zero(I[1])), [ ] ]; fi; ideal := ShallowCopy(I); # indeterminates will be removed from indets and added to removedindets # as we do our reduction indets := ShallowCopy(IndeterminatesOfPolynomialRing(ring)); removedindets := []; removedrelations := []; # Are any of the leading terms of the ideal single indeterminates? # If so then we can (after reduction) remove those indeterminates and those # terms of the ideal repeat indet := false; # Find a relation in the ideal that involves a solitary indeterminate for i in [1..Length(ideal)] do for t in TermsOfPolynomial(ideal[i]) do unimons := UnivariateMonomialsOfMonomial(t[1]); if Length(unimons) = 1 and unimons[1] = IndeterminateOfUnivariateRationalFunction(unimons[1]) then # This term involves a solitary indeterminate. # Check that no other term in this relation also involves this # indeterminate indet := unimons[1]; for t2 in TermsOfPolynomial(ideal[i] - t[1]*t[2]) do if IsOne(DenominatorOfRationalFunction(t2[1] / indet)) then indet := false; break; fi; od; if indet <> false then # We're OK - no other term in this relation involves this # indeterminate, so we can go on to remove it break; fi; fi; od; # Have we found a solitary indeterminate? if indet <> false then relation := Remove(ideal, i); Add(removedrelations, relation); break; fi; od; if indet <> false then # Remove this indeterminate from the indets list and put it # onto the removedindets list instead Remove(indets, Position(indets, indet)); Add(removedindets, indet); # And create a new (temporary) order which has indet as the most important order := MonomialLexOrdering(Concatenation([indet], indets)); # And make sure that our relation has a unit coefficient relation := relation / LeadingCoefficientOfPolynomial(relation, order); # Now reduce all the other relations in the ideal with this one, which # will get rid of this indeterminate i := 1; len := Length(ideal); while i <= len do poly := PolynomialReducedRemainder(ideal[i], [relation], order); if IsZero(poly) then ideal[i] := ideal[len]; Unbind(ideal[len]); len := len - 1; else ideal[i] := poly; i := i + 1; fi; od; fi; until indet = false; # Tidy up the ideal ideal := ReduceIdeal(ideal, MonomialLexOrdering()); # Now make the new ring and convert the indeterminates newring := PolynomialRing(CoefficientsRing(ring), Length(indets), Concatenation(avoid, IndeterminatesOfPolynomialRing(ring))); newrelations := HAPPRIME_SwitchPolynomialIndeterminates( PolynomialRing(CoefficientsRing(ring), indets), newring, ideal); # And remember the mapping map := [indets, ShallowCopy(IndeterminatesOfPolynomialRing(newring))]; if not IsEmpty(removedrelations) then # Finally, sort out the map between the old and new indeterminates # for the removed ones # Start off by adding relations that tell us what the new indeterminates are ideal := IndeterminatesOfPolynomialRing(newring) - indets; # Now add the relations that we have removed Append(ideal, removedrelations); # Create an ordering that puts the removed relations largest so that # they will be removed as much as possible, and the new relations smallest # so they will be kept, then reduce this set of relations ord := MonomialLexOrdering(Concatenation(removedindets, indets, IndeterminatesOfPolynomialRing(newring))); ideal := ReduceIdeal(ideal, ord); # Now add to the map. The polynomials in the ideal that have # leading monomials which still involve the removedindets are the ones # we want removedring := PolynomialRing(CoefficientsRing(ring), removedindets); for i in ideal do if LeadingMonomialOfPolynomial(i, ord) in removedring then # is this a single indeterminate (i.e. a relation of the form x_i)? if Length(TermsOfPolynomial(i)) = 1 then poly := [[i], [Zero(i)]]; else poly := [[], []]; for t in TermsOfPolynomial(i) do if t[1] in ring then Add(poly[1], t[1]*t[2]); elif t[1] in newring then Add(poly[2], t[1]*t[2]); else Error("Relation is not seperable when creating map. Please consult the package maintainer."); fi; od; if IsEmpty(poly[2]) then Error("Unexpected relation with no new indeterminates. Please consult the package maintainer."); fi; fi; Add(map[1], Sum(poly[1])); Add(map[2], Sum(poly[2])); fi; od; fi; return [newring, newrelations, map]; end ); ##################################################################### ################################# ## This functions new to GAP 4.4.10 ## so needs defining if using an earlier version if not IsBound(EmptyPlist) then EmptyPlist := function(n) return []; end; fi; ################################# ##################################################################### ## <#GAPDoc Label="HAPPRIME_SwitchPolynomialIndeterminates_manDTPolynomialInt"> ## <ManSection> ## <Func Name="HAPPRIME_SwitchPolynomialIndeterminates" Arg="R, S, poly"/> ## ## <Returns> ## Polynomial or List of Polynomials ## </Returns> ## <Description> ## Changes the indeterminates in <A>poly</A>, which should be a polynomial or ## a list of polynomials, substituting the indeterminates of the polynomial ## ring <A>S</A> one-for-one for those in <A>R</A> (from which all polynomials ## in <A>poly</A> must come). The returned object is either a polynomial or a ## list of polynomials in the new indeterminates, depending on the input object. ## <P/> ## See <Ref Func="HAPPRIME_MapPolynomialIndeterminates"/> for a function that ## can work with more general indeterminate maps. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallGlobalFunction(HAPPRIME_SwitchPolynomialIndeterminates, function(R, S, polys) local onepoly, Rindetnums, Sindetnums, newpolys, fam, p, extrep, extrepnew, i, j, e; if CoefficientsRing(R) <> CoefficientsRing(S) then Error("<R> and <S> must have the same coefficient ring"); fi; onepoly := false; if Length(IndeterminatesOfPolynomialRing(R)) <> Length(IndeterminatesOfPolynomialRing(S)) then Error("<R> and <S> must have the same number of indeterminates"); fi; if IsEmpty(polys) then return polys; fi; if IsPolynomial(polys) then polys := [polys]; onepoly := true; elif not IsHomogeneousList(polys) then Error("<polys> must be a polynomial or a list of polynomials in <R>"); fi; Rindetnums := List(IndeterminatesOfPolynomialRing(R), IndeterminateNumberOfUnivariateRationalFunction); Sindetnums := List(IndeterminatesOfPolynomialRing(S), IndeterminateNumberOfUnivariateRationalFunction); newpolys := EmptyPlist(Length(polys)); fam := FamilyObj(polys[1]); for p in polys do if not p in R then Error("<polys> must be a polynomial or a list of polynomials in <R>"); fi; extrep := ExtRepPolynomialRatFun(p); extrepnew := EmptyPlist(Length(extrep)); i := 1; repeat e := ShallowCopy(extrep[i]); if not IsEmpty(e) then j := 1; repeat # Swap the indeterminate number e[j] := Sindetnums[Position(Rindetnums, e[j])]; j := j+2; until j > Length(e); fi; Add(extrepnew, e); Add(extrepnew, extrep[i+1]); i := i+2; until i > Length(extrep); Add(newpolys, PolynomialByExtRep(fam, extrepnew)); od; # And sort out the return type if onepoly then return newpolys[1]; else return newpolys; fi; end); ###################################################### ##################################################################### ## <#GAPDoc Label="HAPPRIME_MapPolynomialIndeterminates_manDTPolynomialInt"> ## <ManSection> ## <Func Name="HAPPRIME_MapPolynomialIndeterminates" Arg="old, new, poly"/> ## ## <Returns> ## Polynomial or List of Polynomials ## </Returns> ## <Description> ## Changes the indeterminates in <A>poly</A>, which can be a polynomial or a ## list of polynomials, substituting the polynomials in <A>old</A> for those ## in <A>new</A>. The returned object is either a polynomial or a list of ## polynomials in the new indeterminates, depending on the input object. ## The change of variable arguments, <A>old</A> and <A>new</A>, do not ## have to be simply indeterminates: they can be can be lists of polynomials ## which are equivalent in the two different sets of indeterminates. ## If a polynomial cannot be converted (i.e. if it cannot be generated from the ## polynomials in <A>old</A>) then <K>fail</K> is returned for that polynomial. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallGlobalFunction(HAPPRIME_MapPolynomialIndeterminates, function(old, new, polys) local old2, new2, oldindets, newindets, ord, newpolys, p, newp, onepoly, I, lead, newI, ord2; onepoly := false; if not IsHomogeneousList(old) then Error("<old> must a list of polynomials"); fi; if not IsHomogeneousList(new) then Error("<new> must a list of polynomials"); fi; if Length(old) <> Length(new) then Error("<old> and <new> must both be the same length"); fi; if IsPolynomial(polys) then polys := [polys]; onepoly := true; elif not IsHomogeneousList(polys) then Error("<polys> must be a polynomial or a list of polynomials in the old indeterminates"); fi; oldindets := []; for p in old do UniteSet(oldindets, IndeterminatesOfPolynomial(p)); od; newindets := []; for p in new do UniteSet(newindets, IndeterminatesOfPolynomial(p)); od; if not IsEmpty(Intersection(oldindets, newindets)) then Error("the indeterminates in <old> and <new> must be distinct sets."); fi; # Order the indeterminates so that the old ones are larger, so will # be replaced ord := MonomialLexOrdering(Concatenation(oldindets, newindets)); # Are there any zeros in the old list? If so, remove them and the # corresponding element of the new list old2 := ShallowCopy(old); new2 := ShallowCopy(new); repeat p := Position(old2, Zero(old2[1])); if p <> fail then Remove(old2, p); Remove(new2, p); fi; until p = fail; # The conversion is relations in an ideal. Make sure it is a GroebnerBasis I := HAPPRIME_SingularGroebnerBasis(old2 - new2, ord); # Extract out the relations in the new ring newI := Filtered(I, i->IsSubset(newindets, IndeterminatesOfPolynomial(i))); # and turn this into a Groebner Basis with grevlex ordering ## TODO I would like to make it MonomialGrevlexOrdering here, ## but a bug in that function (reported by me on 27/6/08) means ## that that ordering doesn't work! #ord2 := MonomialGrevlexOrdering(); ord2 := MonomialGrlexOrdering(); newI := HAPPRIME_SingularGroebnerBasis(newI, ord2); newpolys := []; for p in polys do # is this just a constant? lead := LeadingMonomial(p); if IsEmpty(lead) or lead[2] = infinity or lead[2] = 0 then Add(newpolys, p); else # Reduce this. Given the ordering, this will substitute the # new in place of the old # We further reduce this using the grevlex ordering to get the # simplest (smallest degree) form in the new indeterminates newp := PolynomialReducedRemainder( PolynomialReducedRemainder(p, I, ord), newI, ord2); # Check that this really is in the new indeterminates - it might not # be if the map is not complete if not IsSubset(newindets, IndeterminatesOfPolynomial(newp)) then Add(newpolys, fail); else Add(newpolys, newp); fi; fi; od; # And sort out the return type if onepoly then return newpolys[1]; else return newpolys; fi; end); ###################################################### ##################################################################### ## <#GAPDoc Label="HAPPRIME_CombineIndeterminateMaps_manDTPolynomialInt"> ## <ManSection> ## <Func Name="HAPPRIME_CombineIndeterminateMaps" Arg="coeff, M, N"/> ## ## <Returns> ## List ## </Returns> ## <Description> ## Returns the indeterminate map that results from applying map <A>M</A> ## followed by map <A>N</A>. An indeterminate map is a list containing two ## lists, the first of which is a list of polynomials in the original indeterminates, ## the second the equivalent polynomials in the new ring indeterminates. ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### InstallGlobalFunction(HAPPRIME_CombineIndeterminateMaps, function(M, N) local indetsA, indetsB, indetsC, i, ord, I, J, relations, map, poly, t; # Recreate the three rings indetsA := []; indetsB := []; indetsC := []; for i in M[1] do Append(indetsA, IndeterminatesOfPolynomial(i)); od; indetsA := AsSet(indetsA); for i in M[2] do Append(indetsB, IndeterminatesOfPolynomial(i)); od; indetsB := AsSet(indetsB); for i in N[1] do Append(indetsC, IndeterminatesOfPolynomial(i)); od; indetsC := AsSet(indetsC); # Check that the second ring in M and the first in N are compatible if not IsSubset(indetsC, indetsB) and not IsSubset(indetsB, indetsC) then Error("the maps <M> and <N> are incompatible"); fi; indetsC := []; for i in N[2] do Append(indetsC, IndeterminatesOfPolynomial(i)); od; indetsC := AsSet(indetsC); # And check that the three rings are distinct if not IsEmpty(Intersection(indetsA, indetsB)) then Error("the source and target rings of <M> are not different"); fi; if not IsEmpty(Intersection(indetsA, indetsC)) then Error("the source ring of <M> and target ring of <N> are not different"); fi; if not IsEmpty(Intersection(indetsB, indetsC)) then Error("the source and target rings of <N> are not different"); fi; # Order the middle indeterminates first so that they are removed ord := MonomialLexOrdering(Concatenation(indetsB, indetsA, indetsC)); # And get the two set of relations I := M[1] - M[2]; J := N[1] - N[2]; # Now reduce each with the other relations := []; for i in I do Add(relations, PolynomialReducedRemainder(i, J, ord)); od; for i in J do Add(relations, PolynomialReducedRemainder(i, I, ord)); od; relations := AsSet(relations); # Now create the new map. The polynomials in the ideal have # leading monomials which involve the source ring map := [[], []]; for i in relations do poly := [[Zero(i)], [Zero(i)]]; for t in TermsOfPolynomial(i) do if IsSubset(indetsA, IndeterminatesOfPolynomial(t[1])) then Add(poly[1], t[1]*t[2]); elif IsSubset(indetsC, IndeterminatesOfPolynomial(t[1])) then Add(poly[2], t[1]*t[2]); else # This relation still involves an old indeterminate, so we # can't do anything with it - ignore it poly := "ignore"; break; fi; od; if poly <> "ignore" then Add(map[1], Sum(poly[1])); Add(map[2], Sum(poly[2])); fi; od; return map; end); ###################################################### ##################################################################### ## <#GAPDoc Label="HAPPRIME_SingularGroebnerBasis_manDTGroebnerInt"> ## <ManSection> ## <Func Name="HAPPRIME_SingularGroebnerBasis" Arg="pols, O"/> ## <Func Name="HAPPRIME_SingularReducedGroebnerBasis" Arg="pols, O"/> ## ## <Returns> ## List ## </Returns> ## <Description> ## Returns the Gröbner basis (or reduced Gröbner basis) with respect to the ## ordering <A>O</A> for the ideal generated by the polynomials <A>pols</A>. ## This function uses the Gröbner basis implementation ## from &singular;, for preference, if available ## (<Ref Func="GroebnerBasis" BookName="singular"/>), and if so it also ## manuipulates the result to fix a bug in &singular; where the returned ## polynomials are not necessarily returned with a value external ## representation (see ## <Ref Sect="The Defining Attributes of Rational Functions" BookName="ref"/>). ## <P/> ## If the option <C>obeyGBASIS</C> is <K>true</K>, then this function will use ## whichever algorithm is specified by the <K>GBASIS</K> global variable ## (see <Ref Var="SINGULARGBASIS" BookName="singular"/>). ## </Description> ## </ManSection> ## <#/GAPDoc> ##################################################################### #if LoadPackage("singular") = true then if IsPackageMarkedForLoading("singular","0") then InstallGlobalFunction(HAPPRIME_SingularGroebnerBasis, function(pols, O) local gbasis, ideal, fam; # If empty, do nothing if IsEmpty(pols) then return pols; fi; # Make sure we use Singular gbasis := GBASIS; if not ValueOption("obeyGBASIS") = true then GBASIS := SINGULARGBASIS; fi; ideal := GroebnerBasis(pols, O); GBASIS := gbasis; # Hack to make sure that the polynomials returned by Singular are correct fam := FamilyObj(pols[1]); return List(ideal, x->PolynomialByExtRep(fam, ExtRepPolynomialRatFun(x)));; end ); ##################################################################### InstallGlobalFunction(HAPPRIME_SingularReducedGroebnerBasis, function(pols , O) local ipr, mcf, R, I, input, out, fam; # If empty, do nothing if IsEmpty(pols) then return pols; fi; if ValueOption("obeyGBASIS") = true and GBASIS = GAPGBASIS then return ReducedGroebnerBasis(pols, O); fi; if IsPolynomialRingIdeal(pols) then R := LeftActingRingOfIdeal(pols); pols := GeneratorsOfTwoSidedIdeal(pols); else R := DefaultRing(pols); fi; if IsMonomialOrdering(O) then ipr := ShallowCopy(IndeterminatesOfPolynomialRing(R)); mcf := MonomialComparisonFunction(O); Sort(ipr, mcf); ipr := Reversed(ipr); R := PolynomialRing(LeftActingDomain(R), ipr); fi; if not(HasTermOrdering(R) and IsIdenticalObj(TermOrdering(R), O)) then SetTermOrdering(R, O); SingularSetBaseRing(R); fi; I := Ideal(R, pols); # Now use Singular to find the Groebner Basis Info( InfoSingular, 2, "running GroebnerBasis..." ); SingularCommand("", "option(redSB)"); # preparing the input for Singular input := ""; Append( input, "ideal GAP_groebner = simplify( groebner( " ); Append( input, ParseGapIdealToSingIdeal( I ) ); Append( input, " ), 1 );\n" ); out := SingularCommand( input, "string (GAP_groebner)" ); SingularCommand("", "option(noredSB)"); Info( InfoSingular, 2, "done GroebnerBasis." ); I := List( SplitString( out, ',' ), ParseSingPolyToGapPoly ); # Hack to make sure that the polynomials returned by Singular are correct fam := FamilyObj(pols[1]); return List(I, x->PolynomialByExtRep(fam, ExtRepPolynomialRatFun(x)));; end ); else InstallGlobalFunction(HAPPRIME_SingularGroebnerBasis, function(I, O) return GroebnerBasis(I, O); end ); InstallGlobalFunction(HAPPRIME_SingularReducedGroebnerBasis, function(I, O) return ReducedGroebnerBasis(I, O); end ); fi; #####################################################################