code / alex / psage / psage / modform / fourier_expansion_framework / gradedexpansions / gradedexpansion_functor.py
241849 viewsr"""1Functors for ring and modules of graded expansions.23AUTHOR :4-- Martin Raum (2009 - 07 - 27) Initial version5"""67#===============================================================================8#9# Copyright (C) 2009 Martin Raum10#11# This program is free software; you can redistribute it and/or12# modify it under the terms of the GNU General Public License13# as published by the Free Software Foundation; either version 314# of the License, or (at your option) any later version.15#16# This program is distributed in the hope that it will be useful,17# but WITHOUT ANY WARRANTY; without even the implied warranty of18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU19# General Public License for more details.20#21# You should have received a copy of the GNU General Public License22# along with this program; if not, see <http://www.gnu.org/licenses/>.23#24#===============================================================================2526from itertools import groupby, dropwhile27from sage.algebras.algebra import Algebra28from sage.categories.morphism import Morphism29from sage.categories.pushout import ConstructionFunctor, pushout30from sage.categories.rings import Rings31from sage.misc.misc import prod32from sage.modules.module import Module33from sage.rings.integer import Integer34from sage.structure.sequence import Sequence35import operator3637#===============================================================================38# GradedExpansionFunctor39#===============================================================================4041class GradedExpansionFunctor ( ConstructionFunctor ) :42r"""43Constructing a graded expansion ring or module from a base ring.44"""4546rank = 104748def __init__( self, base_ring_generators, generators,49relations, grading, all_relations = True, reduce_before_evaluating = True ) :50r"""51INPUT:52- ``base_ring_generators`` -- A sequence of (equivariant) monoid power series with53coefficient domain the base ring of the coefficient54domain of the generators or ``None``.55- ``generators`` -- A sequence of (equivariant) monoid power series; The generators56of the ambient over the ring generated by the base ring57generators.58- ``relations`` -- An ideal in a polynomial ring with ``len(base_ring_generators) + len(generators)``59variables.60- ``grading`` -- A grading deriving from :class:~`fourier_expansion_framework.gradedexpansions.gradedexpansion_grading`;61A grading for the polynomial ring of the relations.62- ``all_relations`` -- A boolean (default: ``True``); If ``True`` the relations given63for the polynomial ring are all relations that the Fourier64expansion have.65- ``reduce_before_evaluating`` -- A boolean (default: ``True``); If ``True`` any monomial66will be Groebner reduced before the Fourier expansion67is calculated.6869NOTE:70The grading must respect the relations of the generators.7172TESTS::73sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *74sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *75sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *76sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading77sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *78sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))79sage: funct = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))80"""81if grading.ngens() != relations.ring().ngens() :82raise ValueError( "Grading must have the same number of variables as the relations' polynomial ring." )8384self.__relations = relations85self.__grading = grading86self.__all_relations = all_relations87self.__reduce_before_evaluating = reduce_before_evaluating8889self.__gen_expansions = Sequence(generators)90if base_ring_generators is None :91self.__base_gen_expansions = Sequence([], universe = self.__gen_expansions.universe().base_ring())92else :93self.__base_gen_expansions = Sequence(base_ring_generators)9495if len(self.__base_gen_expansions) == 0 :96scalar_ring = self.__gen_expansions.universe().base_ring()97if self.__gen_expansions.universe().coefficient_domain() != self.__gen_expansions.universe().base_ring() :98scalar_ring = self.__gen_expansions.universe().base_ring().base_ring()99else :100scalar_ring = self.__gen_expansions.universe().base_ring()101else :102scalar_ring = self.__base_gen_expansions.universe().base_ring()103104if not relations.base_ring().has_coerce_map_from(scalar_ring) :105raise ValueError( "The generators must be defined over the base ring of relations" )106107if not isinstance(self.__gen_expansions.universe(), Algebra) and \108not isinstance(self.__gen_expansions.universe(), Module) :109raise TypeError( "The generators' universe must be an algebra or a module" )110111ConstructionFunctor.__init__( self, Rings(), Rings() )112113def __call__(self, R) :114r"""115The graded expansion ring with the given generators over the base116ring `R`.117118INPUT:119- `R` -- A ring.120121OUTPUT:122An instance of :class:~`fourier_expansion_framework.gradedexpansions.gradedexpansion_ambient.GradedExpansion_abstract`.123124NOTE:125The ring of Fourier expansions given by the generators associated126with this functor must admit a base extension to `R`.127128TESTS::129sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *130sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *131sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *132sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *133sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading134sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *135sage: K.<rho> = CyclotomicField(6)136sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))137sage: funct = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))138sage: funct(K)139Graded expansion ring with generators b140sage: m = FreeModule(QQ, 3)141sage: mpsm = MonoidPowerSeriesModule(m, NNMonoid(False))142sage: mps = mpsm.base_ring()143sage: funct = GradedExpansionFunctor(None, Sequence([MonoidPowerSeries(mpsm, {1 : m([1,2,3]), 2 : m([3,-3,2])}, mpsm.monoid().filter(4)), MonoidPowerSeries(mpsm, {1 : m([2,-1,-1]), 2 : m([1,0,0])}, mpsm.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))144sage: funct(K)145Graded expansion module with generators a, b146"""147from gradedexpansion_ring import GradedExpansionRing_class148from gradedexpansion_module import GradedExpansionModule_class149150R = pushout(self.__relations.ring(), R)151rel = R.ideal(self.__relations.gens())152153if isinstance(self.__gen_expansions.universe(), Algebra) :154return GradedExpansionRing_class( self.__base_gen_expansions, self.__gen_expansions,155rel, self.__grading, self.__all_relations, self.__reduce_before_evaluating )156elif isinstance(self.__gen_expansions.universe(), Module) :157return GradedExpansionModule_class( self.__base_gen_expansions, self.__gen_expansions,158rel, self.__grading, self.__all_relations, self.__reduce_before_evaluating )159160raise RuntimeError( "The generators' universe must be an algebra or a module." )161162def __cmp__(self, other) :163r"""164TESTS::165sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *166sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *167sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *168sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading169sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *170sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))171sage: funct = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))172sage: funct == GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))173True174sage: funct == GradedExpansionFunctor(None, Sequence([MonoidPowerSeries(mps, {1 : 4, 2 : 3}, mps.monoid().filter(4)), MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,3)))175False176sage: P.<a,b> = PolynomialRing(QQ)177sage: funct == GradedExpansionFunctor(None, Sequence([MonoidPowerSeries(mps, {1 : 4, 2 : 3}, mps.monoid().filter(4)), MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), P.ideal(a^2 - b), DegreeGrading((1,2)))178False179sage: funct == GradedExpansionFunctor(None, Sequence([MonoidPowerSeries(mps, {1 : 4, 2 : 3}, mps.monoid().filter(4)), MonoidPowerSeries(mps, {1 : 1, 2 : 4}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))180False181sage: funct == GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1 : 4}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1 : 4, 2 : 3}, mps.monoid().filter(4)), MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b', 'c']).ideal(0), DegreeGrading((1,2,2)))182False183"""184c = cmp(type(self), type(other))185if c == 0 :186c = cmp(self.__relations, other.__relations)187if c == 0 :188c = cmp(self.__all_relations, other.__all_relations)189if c == 0 :190c = cmp(self.__grading, other.__grading)191if c == 0 :192c = cmp(self.__base_gen_expansions, other.__base_gen_expansions)193if c == 0 :194c = cmp(self.__gen_expansions, other.__gen_expansions)195196return c197198def merge(self, other) :199r"""200TESTS::201sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *202sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *203sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *204sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading205sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *206sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))207sage: funct = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))208sage: funct.merge(funct) is None209False210sage: funct2 = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((3,2)))211sage: funct.merge(funct2) is None212True213sage: funct2 = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 2}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))214sage: funct.merge(funct2) is None215True216sage: K.<rho> = CyclotomicField(6)217sage: funct2 = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(K, ['a', 'b']).ideal(0), DegreeGrading((1,2)))218sage: funct2.merge(funct) is None219False220"""221#TODO: Implement merging of base rings222if self == other :223return self224225if self.__all_relations != other.__all_relations or \226self.__grading != other.__grading or \227self.__base_gen_expansions != other.__base_gen_expansions or \228self.__gen_expansions != other.__gen_expansions :229return None230231if self.__relations.ring().has_coerce_map_from(other.__relations.ring()) and \232self.__relations == self.__relations.ring().ideal(other.__relations.gens()) :233return self234235return None236237#===============================================================================238# GradedExpansionBaseringInjection239#===============================================================================240241class GradedExpansionBaseringInjection ( Morphism ) :242r"""243The injection of the base ring into a ring of graded expansions.244"""245246def __init__(self, domain, codomain ) :247r"""248INPUT:249- ``domain`` -- A ring.250- ``codomain`` -- A ring of graded expansions.251252TESTS::253sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *254sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *255sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *256sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading257sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *258sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *259sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))260sage: ger = GradedExpansionRing_class(None, Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4)), MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))261sage: GradedExpansionBaseringInjection(QQ, ger)262Base ring injection of Graded expansion ring with generators a, b morphism:263From: Rational Field264To: Graded expansion ring with generators a, b265"""266Morphism.__init__(self, domain, codomain)267268self._repr_type_str = "Base ring injection of %s" % (codomain,)269270def _call_(self, x) :271r"""272INPUT:273- `x` -- An element of the domain.274275OUTPUT:276An element of the codomain.277278TESTS::279sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *280sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *281sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *282sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading283sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *284sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *285sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))286sage: ger = GradedExpansionRing_class(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))287sage: inj = GradedExpansionBaseringInjection(ger.base_ring(), ger)288sage: inj(ger.base_ring()(2))289Graded expansion 2290"""291return self.codomain()._element_constructor_(x)292293def _call_with_args(self, x, *args, **kwds):294r"""295INPUT:296- `x` -- An element of the domain.297- `args`` -- Will be forwarded to the codomain's element constructor.298- ``kwds`` -- Will be forwarded to the codomain's element constructor.299300OUTPUT:301An element of the codomain.302303TESTS::304sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *305sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *306sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *307sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading308sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *309sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *310sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))311sage: ger = GradedExpansionRing_class(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))312sage: inj = GradedExpansionBaseringInjection(ger.base_ring(), ger)313sage: h = inj(ger.base_ring()(0))314"""315return self.codomain()._element_constructor_(x, *args, **kwds)316317#===============================================================================318# GradedExpansionEvaluationHomomorphism319#===============================================================================320321class GradedExpansionEvaluationHomomorphism ( Morphism ) :322r"""323The evaluation of a polynomial by substituting the Fourier expansions324attached to a ring or module of graded expansions.325"""326327def __init__(self, relations, base_ring_images, images, codomain, reduce = True) :328r"""329INPUT:330- ``relations`` -- An ideal in a polynomial ring.331- ``base_ring_images`` -- A list or sequence of elements of a ring of (equivariant)332monoid power series.333- ``images`` -- A list or sequence of monoid power series.334- ``codomain`` -- An ambient of (equivariant) monoid power series.335- ``reduce`` -- A boolean (default: ``True``); If ``True`` polynomials will336be reduced before the substitution is carried out.337338TESTS::339sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *340sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *341sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *342sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading343sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *344sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *345sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))346sage: ev = GradedExpansionEvaluationHomomorphism(PolynomialRing(QQ, ['a', 'b']).ideal(0), Sequence([MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(2))]), Sequence([MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), mps, False)347"""348self.__relations = relations349self.__base_ring_images = base_ring_images350self.__images = images351self.__reduce = reduce352353Morphism.__init__(self, relations.ring(), codomain)354355self._repr_type_str = "Evaluation homomorphism from %s to %s" % (relations.ring(), codomain)356357def _call_with_args(self, x, *args, **kwds) :358r"""359SEE:360:meth:~`._call_`.361362NOTE:363``args`` and ``kwds`` will be ignored.364365TESTS::366sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *367sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *368sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *369sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading370sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *371sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *372sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))373sage: P.<a,b> = QQ[]374sage: ev = GradedExpansionEvaluationHomomorphism(P.ideal(0), Sequence([MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(2))]), Sequence([MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), mps, False)375sage: h = ev(a, h = True)376"""377return self._call_(x)378379def _call_(self, x) :380r"""381INPUT:382- `x` -- A polynomial.383384OUTPUT:385An element of the codomain.386387TESTS::388sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *389sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *390sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *391sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading392sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *393sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *394sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))395sage: P.<a,b> = QQ[]396sage: ev = GradedExpansionEvaluationHomomorphism(P.ideal(0), Sequence([MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(2))]), Sequence([MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), mps, False)397sage: ev(a)398Monoid power series in Ring of monoid power series over NN399sage: ev = GradedExpansionEvaluationHomomorphism(P.ideal(a - b), Sequence([MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(2))]), Sequence([MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), mps, True)400sage: ev(a - b).coefficients()401{0: 0}402"""403if self.__reduce :404x = self.__relations.reduce(x)405406## Be careful not to directly substitute the elements of self.__images407## into the polynomial since they might be vectors, hence yielding408## an exception.409410#=======================================================================411# if len(self.__base_ring_images) == 0 :412# parent = self.__images.universe()413# res = parent(0)414#415# for imexps,c in x.dict().iteritems() :416# if isinstance(imexps, int) :417# imexps = (imexps,)418# imexps = tuple(imexps)419#420# if imexps.count(0) == len(imexps) :421# res = res + c * parent(Integer(1))422# # this is the typical module case with an action423# # that does not respect the monoid structure424# elif imexps.count(0) == len(imexps) - 1 :425# i,e = dropwhile(lambda (_,e) : e == 0, enumerate(imexps)).next()426# if e == 1 :427# res = res + c * self.__images[i]428# else :429# res = res + c * self.__images[i]**e430# else :431# res = res + prod(map(operator.pow, self.__images, imexps))432#433# return res434#=======================================================================435436expansion_ambient = self.__images.universe()437res = self.__images.universe().zero_element()438439coeffs = x.dict()440xexps = groupby( sorted(x.exponents()),441lambda e: ([e] if isinstance(e, int) else list(e))[len(self.__base_ring_images):] )442443for imexps, exps in xexps :444factor = self.__base_ring_images.universe().zero_element()445for e in exps :446factor = factor + coeffs[e] * prod(map( operator.pow, self.__base_ring_images,447([e] if isinstance(e,int) else e)[:len(self.__base_ring_images)] ))448449imexps = tuple(imexps)450451if imexps.count(0) == len(imexps) :452res = res + factor * expansion_ambient.one_element()453elif imexps.count(0) == len(imexps) - 1 :454i,e = dropwhile(lambda (_,e) : e == 0, enumerate(imexps)).next()455# this is the typical module case with an action456# that does not respect the monoid structure457if e == 1 :458res = res + factor * self.__images[i]459else :460res = res + factor * self.__images[i]**e461else :462res = res + factor * prod(map(operator.pow, self.__images, imexps))463464return res465466467