code / alex / psage / psage / modform / fourier_expansion_framework / monoidpowerseries / monoidpowerseries_element.py
241852 viewsr"""1Monoid power series and equivariant monoid power series.23AUTHOR :4-- Martin Raum (2009 - 07 - 25) 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 copy import copy27from sage.algebras.algebra_element import AlgebraElement28from sage.misc.latex import latex29from sage.misc.misc import union30from sage.modules.module import Module31from sage.modules.module_element import ModuleElement32from sage.rings.ring import Ring3334#===============================================================================35# MonoidPowerSeries36#===============================================================================3738def MonoidPowerSeries( parent, coefficients, precision, cleanup_coefficients = False) :39r"""40Create a monoid power series within a given parent.4142INPUT:43- ``parent`` -- A ring or module of monoid power series.44- ``coefficients`` -- A dictionary with keys in the parent's monoid and values45in the parent coefficient domain.46- ``precision`` -- A filter for the parent's monoid.47- ``cleanup_coefficients`` -- A boolean (default: ``False``); If ``True`` zero48coefficients will be erased from the dictionary.4950OUTPUT:51An instance of :class:~`.MonoidPowerSeries_abstract`.5253EXAMPLES::54sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *55sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *56sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *57sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *58sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))59sage: h = MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(3))6061TESTS::62sage: h = MonoidPowerSeries(mps, {1 : 1}, mps.monoid().zero_filter(), True)63sage: h = MonoidPowerSeries(mps, {1 : 4, 0 : 3}, mps.monoid().filter_all())64sage: mps = MonoidPowerSeriesModule(FreeModule(QQ, 2), NNMonoid(False))65sage: h = MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(3))66"""67if isinstance(parent, Module) :68return MonoidPowerSeries_moduleelement(parent, coefficients, precision, cleanup_coefficients)69if isinstance(parent, Ring) :70return MonoidPowerSeries_algebraelement(parent, coefficients, precision, cleanup_coefficients)7172raise TypeError, "Unexpected type of parent"7374#===============================================================================75# MonoidPowerSeries_abstract76#===============================================================================7778class MonoidPowerSeries_abstract :79r"""80An element of the monoid power series ring or module up to81given precision.82"""8384def __init__(self, parent, precision) :85r"""86INPUT:87- ``parent`` -- An instance of :class:~`fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.MonoidPowerSeriesAmbient_abstract`.88- ``precision`` -- A filter associated to the parent's monoid.8990TESTS::91sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *92sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *93sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *94sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))95sage: h = MonoidPowerSeries_abstract(mps, mps.monoid().zero_filter())96"""97self.__precision = parent.monoid().filter(precision)9899def precision(self) :100r"""101The series' precision.102103OUTPUT:104A filter for the parent's monoid.105106TESTS::107sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *108sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *109sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *110sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))111sage: MonoidPowerSeries_abstract(mps, mps.monoid().zero_filter()).precision() == mps.monoid().zero_filter()112True113"""114return self.__precision115116def _set_precision(self, precision) :117r"""118Set the series' precision.119120INPUT:121- ``precision`` -- A filter for the parent's monoid or a an object that can be converted122to a filter.123124TESTS::125sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *126sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *127sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *128sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))129sage: h = copy(mps.one_element())130sage: h._set_precision(mps.monoid().filter(2))131sage: h.precision() == mps.monoid().filter(2)132True133sage: h._set_precision(3)134sage: h.precision() == mps.monoid().filter(3)135True136"""137self.__precision = self.parent().monoid().filter(precision)138139def _bounding_precision(self) :140r"""141If ``self.precision()`` is an infinite filter, return a filter142which contains all non zero coefficients of this series. Otherwise,143return ``self.precision()``144145OUTPUT:146A filter for the parent's monoid.147148TESTS::149sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *150sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *151sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *152sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))153sage: h = MonoidPowerSeries(mps, dict(), mps.monoid().filter(2))154sage: h._bounding_precision() == mps.monoid().filter(2)155True156sage: h = MonoidPowerSeries(mps, dict(), mps.monoid().filter_all())157sage: h._bounding_precision() == mps.monoid().zero_filter()158True159"""160if not self.precision().is_infinite() :161return self.precision()162163return self.parent().monoid().minimal_composition_filter( self.coefficients().keys(),164[self.parent().monoid().zero_element()] )165166def coefficients(self) :167r"""168The coefficients of ``self``.169170OUTPUT:171A dictionary with keys the elements of the parent's monoid and values in the172parent's coefficient domain.173174TESTS::175sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *176sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *177sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *178sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))179sage: MonoidPowerSeries_abstract(mps, mps.monoid().filter_all()).coefficients()180Traceback (most recent call last):181...182NotImplementedError183"""184raise NotImplementedError185186def _truncate_in_place(self, precision) :187r"""188Truncate ``self`` modifying the coefficient dictionary directly.189190INPUT:191- ``precision`` -- A filter for the parent's monoid or a an object that can be converted192to a filter.193194OUTPUT:195``None``196197TESTS::198sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *199sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *200sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *201sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))202sage: MonoidPowerSeries_abstract(mps, mps.monoid().filter_all())._truncate_in_place(mps.monoid().zero_filter())203Traceback (most recent call last):204...205NotImplementedError206"""207raise NotImplementedError208209def truncate(self, precision) :210r"""211Truncate a copy of ``self``.212213INPUT:214- ``precision`` -- A filter for the parent's monoid or a an object that can be converted215to a filter.216217OUTPUT:218An instance of :class:~`.MonoidPowerSeries_abstract_nonlazy`.219220TESTS::221sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *222sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *223sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *224sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))225sage: MonoidPowerSeries_abstract(mps, mps.monoid().filter_all()).truncate(mps.monoid().zero_filter())226Traceback (most recent call last):227...228NotImplementedError229"""230raise NotImplementedError231232def _add_(left, right) :233r"""234TESTS::235sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *236sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *237sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *238sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))239sage: mps.one_element() == mps.one_element() + MonoidPowerSeries(mps, dict(), mps.monoid().filter_all())240True241"""242prec = min(left.__precision, right.__precision)243lcoeffs = left.coefficients()244rcoeffs = right.coefficients()245246lkeys = set(lcoeffs)247rkeys = set(rcoeffs)248249d = dict()250for k in lkeys - rkeys :251d[k] = lcoeffs[k]252for k in rkeys - lkeys :253d[k] = rcoeffs[k]254for k in lkeys.intersection(rkeys) :255d[k] = lcoeffs[k] + rcoeffs[k]256257return MonoidPowerSeries(left.parent(), d, prec)258259def _mul_(left, right, switch_factors = False) :260r"""261NOTE:262This function has to accept algebra and module elements and will263also compute the action of the base ring (which might be a monoid power series)264on a module.265266TESTS::267sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *268sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *269sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *270sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))271sage: mps.one_element() * mps.one_element() == mps.one_element()272True273"""274mul_fc = left.parent()._multiply_function()275276if not switch_factors :277lcoeffs = left.coefficients()278rcoeffs = right.coefficients()279else :280lcoeffs = right.coefficients()281rcoeffs = left.coefficients()282283prec = min(left.precision(), right.precision())284if prec.is_infinite() :285if len(lcoeffs) == 0 or len(rcoeffs) == 0:286return MonoidPowerSeries(left.parent(), dict(), prec)287iter_prec = left.parent().monoid(). \288minimal_composition_filter(set(lcoeffs), set(rcoeffs))289else :290iter_prec = prec291292d = dict()293for k in iter_prec :294v = mul_fc( k, lcoeffs, rcoeffs,295left.parent().coefficient_domain().zero_element() )296if not v.is_zero() :297d[k] = v298299return MonoidPowerSeries(left.parent(), d, prec)300301def _lmul_(self, c) :302r"""303TESTS::304sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *305sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *306sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *307sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *308sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))309sage: (mps.one_element() * 2) * 3 == mps.one_element() * 6310True311sage: m = FreeModule(QQ, 3)312sage: mpsm = MonoidPowerSeriesModule(m, NNMonoid(False))313sage: h = MonoidPowerSeries(mps, {1 : 1, 3 : 2}, mps.monoid().filter(4))314sage: hv = MonoidPowerSeries(mpsm, {1 : m([1,0,0]), 2 : m([0,1,0])}, mps.monoid().filter(4))315sage: hh = hv * h316"""317if c.is_zero() :318return MonoidPowerSeries(self.parent(), dict(), None)319320if isinstance(c, MonoidPowerSeries_abstract) and not isinstance(self, AlgebraElement) :321coeffs = c.coefficients()322if len(coeffs) == 1 and self.parent().monoid().zero_element() in coeffs :323c = coeffs[self.parent().monoid().zero_element()]324d = dict((k, c*v) for (k,v) in self.coefficients().iteritems())325326return MonoidPowerSeries(self.parent(), d, self.precision())327328return self._mul_(c, False)329else :330d = dict((k, c*v) for (k,v) in self.coefficients().iteritems())331332return MonoidPowerSeries(self.parent(), d, self.precision())333334def _rmul_(self, c) :335r"""336TESTS::337sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *338sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *339sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *340sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *341sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))342sage: 3 * (2 * mps.one_element()) == 6 * mps.one_element()343True344sage: m = FreeModule(QQ, 3)345sage: mpsm = MonoidPowerSeriesModule(m, NNMonoid(False))346sage: h = MonoidPowerSeries(mps, {1 : 1, 3 : 2}, mps.monoid().filter(4))347sage: hv = MonoidPowerSeries(mpsm, {1 : m([1,0,0]), 2 : m([0,1,0])}, mps.monoid().filter(4))348sage: hh = h * hv349"""350351if c.is_zero() :352return MonoidPowerSeries(self.parent(), dict(), None)353354if isinstance(c, MonoidPowerSeries_abstract) and not isinstance(self, AlgebraElement) :355coeffs = c.coefficients()356if len(coeffs) == 1 and self.parent().monoid().zero_element() in coeffs :357c = coeffs[self.parent().monoid().zero_element()]358d = dict((k, v*c) for (k,v) in self.coefficients().iteritems())359360return MonoidPowerSeries(self.parent(), d, self.precision())361362return self._mul_(c, True)363else :364d = dict((k, v*c) for (k,v) in self.coefficients().iteritems())365366return MonoidPowerSeries(self.parent(), d, self.precision())367368def __contains__(self, k) :369r"""370Check whether `k` is below the series' precision.371372INPUT:373- `k` -- An element of the parent's monoid.374375OUTPUT:376A boolean.377378TESTS::379sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *380sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *381sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *382sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))383sage: 2 in mps.one_element()384True385sage: 1 in mps.one_element().truncate(mps.monoid().zero_filter())386False387"""388return k in self.precision()389390def __getitem__(self, s) :391r"""392Return the `k`-th coefficient if it below the series' precision.393394INPUT:395- `k` -- An element of the parent's monoid.396397OUTPUT:398An element of the parent's coefficient domain.399400TESTS::401sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *402sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *403sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *404sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))405sage: MonoidPowerSeries_abstract(mps, mps.monoid().filter_all())[0]406Traceback (most recent call last):407...408NotImplementedError409"""410raise NotImplementedError411412def __cmp__(self, other) :413r"""414TESTS::415sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *416sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *417sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *418sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))419sage: mps.one_element() == mps.one_element()420True421sage: mps.one_element() == mps.zero_element()422False423"""424425c = cmp(self.precision(), other.precision())426if c != 0 : return c427428self_coeffs = self.coefficients()429other_coeffs = other.coefficients()430self_keys = set(self_coeffs)431other_keys = set(other_coeffs)432433for k in self_keys - other_keys :434if not self_coeffs[k].is_zero() :435return -1436for k in other_keys - self_keys :437if not other_coeffs[k].is_zero() :438return -1439for k in self_keys.intersection(other_keys) :440if self_coeffs[k] != other_coeffs[k] :441return -1442443return 0444445def _repr_(self) :446r"""447TESTS::448sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *449sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *450sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *451sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))452sage: mps.one_element() # indirect doctest453Monoid power series in Ring of monoid power series over NN454"""455return "Monoid power series in %s" % self.parent()456457def _latex_(self) :458r"""459TESTS::460sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *461sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *462sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *463sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))464sage: latex(mps.one_element()) # indirect doctest465\text{Monoid power series in } \text{Ring of monoid power series over }\Bold{N}466"""467return r"\text{Monoid power series in }" + latex(self.parent())468469#===============================================================================470# MonoidPowerSeries_abstract_nonlazy471#===============================================================================472473class MonoidPowerSeries_abstract_nonlazy (MonoidPowerSeries_abstract) :474r"""475A abstract implementation of monoid power series that store their coefficients.476"""477478def __init__(self, parent, coefficients, precision, cleanup_coefficients) :479r"""480INPUT:481- ``parent`` -- An instance of :class:~`fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.MonoidPowerSeriesAmbient_abstract`.482- ``coefficients`` -- A dictionary with keys in the parent's monoid and values483in the parent coefficient domain.484- ``precision`` -- A filter associated to the parent's monoid.485- ``cleanup_coefficients`` -- A boolean; If ``True`` zero coefficients will be486erased from the dictionary.487488TESTS::489sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *490sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *491sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *492sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))493sage: h = MonoidPowerSeries_abstract_nonlazy(mps, dict(), mps.monoid().zero_filter(), False)494"""495MonoidPowerSeries_abstract.__init__(self, parent, precision)496497if cleanup_coefficients and len(coefficients) != 0 :498coefficients = self._cleanup_coefficients( coefficients, in_place = True )499500self.__coefficients = coefficients501502def coefficients(self) :503r"""504The coefficients of ``self``.505506OUTPUT:507A dictionary with keys the elements of the parent's monoid and values in the508parent's coefficient domain.509510NOTE:511Some keys may be invalid. To get an exact result512call ``_cleanup_coefficients(in_place = True)`` before.513514TESTS::515sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *516sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *517sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *518sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))519sage: mps.one_element().coefficients()520{0: 1}521"""522return self.__coefficients523524def _cleanup_coefficients(self, coefficients = None, in_place = True) :525r"""526Remove zero entries and entries not below ``self.precision()`` from a coefficient dictionary.527528INPUT:529- ``coefficients`` -- ``None`` or a dictionary (default: ``None``); If ``None`` the530coefficient dictionary assigned to ``self`` will be cleaned.531- ``in_place`` -- A boolean (default: ``True``); If ``False`` a copy of the coefficient532dictionary will me cleaned and returned.533534OUTPUT:535A dictionary with keys the elements of the parent's monoid and values in the536parent's coefficient domain.537538TESTS::539sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *540sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *541sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *542sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))543sage: mps.one_element()._cleanup_coefficients()544{0: 1}545sage: d = {1 : 1}546sage: tmp = MonoidPowerSeries(mps, dict(), mps.monoid().zero_filter())._cleanup_coefficients(d)547sage: d548{}549sage: mps.zero_element()._cleanup_coefficients({1 : 0}, False)550{}551sage: h = copy(mps.one_element())552sage: h._set_precision(mps.monoid().zero_filter())553sage: h._cleanup_coefficients(in_place = False)554{}555"""556if coefficients is None :557coefficients = self.__coefficients558559if in_place :560for s in coefficients.keys() :561if not s in self.precision() or coefficients[s].is_zero() :562del coefficients[s]563else :564ncoefficients = dict()565566for s in coefficients :567if not s in self.precision() : continue568569v = coefficients[s]570if v.is_zero() : continue571572ncoefficients[s] = v573574if in_place :575return coefficients576else :577return ncoefficients578579def _truncate_in_place(self, precision) :580r"""581Truncate ``self`` modifying the coefficient dictionary directly.582583INPUT:584- ``precision`` -- A filter for the parent's monoid or a an object that can be converted585to a filter.586587OUTPUT:588``None``589590TESTS::591sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *592sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *593sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *594sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))595sage: h = copy(mps.one_element())596sage: h._truncate_in_place(mps.monoid().zero_filter())597sage: h.coefficients()598{}599sage: h = copy(mps.one_element())600sage: h._truncate_in_place(0)601sage: h.coefficients()602{}603"""604precision = self.parent().monoid().filter(precision)605nprec = min(self.precision(), precision)606607if nprec != self.precision() :608coefficients = self.__coefficients609for k in coefficients.keys() :610if not k in nprec :611del coefficients[k]612613self._set_precision(nprec)614615def truncate(self, precision) :616r"""617Truncate a copy of ``self``.618619INPUT:620- ``precision`` -- A filter for the parent's monoid or a an object that can be converted621to a filter.622623OUTPUT:624An instance of :class:~`.MonoidPowerSeries_abstract_nonlazy`.625626TESTS::627sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *628sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *629sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *630sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))631sage: mps.one_element().truncate(mps.monoid().zero_filter()).coefficients()632{}633sage: mps.one_element().truncate(0).coefficients()634{}635"""636precision = self.parent().monoid().filter(precision)637nprec = min(self.precision(), precision)638639ncoefficients = copy(self.__coefficients)640return MonoidPowerSeries( self.parent(), ncoefficients, nprec, cleanup_coefficients = True )641642def __getitem__(self, s) :643r"""644Return the `k`-th coefficient if it below the series' precision.645646INPUT:647- `k` -- An element of the parent's monoid.648649OUTPUT:650An element of the parent's coefficient domain.651652TESTS::653sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *654sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *655sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *656sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))657sage: MonoidPowerSeries_abstract_nonlazy(mps, { 0 : 10, 1 : 1 }, mps.monoid().filter_all(), False)[0]65810659"""660try :661return self.coefficients()[s]662except KeyError :663return self.parent().coefficient_domain().zero_element()664665#===============================================================================666# MonoidPowerSeries_moduleelement667#===============================================================================668669class MonoidPowerSeries_moduleelement ( MonoidPowerSeries_abstract_nonlazy, ModuleElement ) :670r"""671An element of a module of monoid power series.672"""673674def __init__(self, parent, coefficients, precision, cleanup_coefficients) :675r"""676INPUT:677- ``parent`` -- An instance of :class:~`fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.MonoidPowerSeriesAmbient_abstract`.678- ``coefficients`` -- A dictionary with keys in the parent's monoid and values679in the parent coefficient domain.680- ``precision`` -- A filter associated to the parent's monoid.681- ``cleanup_coefficients`` -- A boolean; If ``True`` zero coefficients will be682erased from the dictionary.683684TESTS::685sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *686sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *687sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *688sage: mps = MonoidPowerSeriesModule(FreeModule(QQ, 2), NNMonoid(False))689sage: h = MonoidPowerSeries_moduleelement(mps, dict(), mps.monoid().zero_filter(), False)690"""691ModuleElement.__init__(self, parent)692MonoidPowerSeries_abstract_nonlazy.__init__(self, parent, coefficients, precision, cleanup_coefficients)693694#===============================================================================695# MonoidPowerSeries_algebraelement696#===============================================================================697698class MonoidPowerSeries_algebraelement ( MonoidPowerSeries_abstract_nonlazy, AlgebraElement ) :699r"""700An element of a algebra of monoid power series.701"""702703def __init__(self, parent, coefficients, precision, cleanup_coefficients) :704r"""705INPUT:706- ``parent`` -- An instance of :class:~`fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.MonoidPowerSeriesAmbient_abstract`.707- ``coefficients`` -- A dictionary with keys in the parent's monoid and values708in the parent coefficient domain.709- ``precision`` -- A filter associated to the parent's monoid.710- ``cleanup_coefficients`` -- A boolean; If ``True`` zero coefficients will be711erased from the dictionary.712713TESTS::714sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *715sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *716sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *717sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))718sage: h = MonoidPowerSeries_algebraelement(mps, dict(), mps.monoid().zero_filter(), False)719"""720AlgebraElement.__init__(self, parent)721MonoidPowerSeries_abstract_nonlazy.__init__(self, parent, coefficients, precision, cleanup_coefficients)722723#===============================================================================724# EquivariantMonoidPowerSeries725#===============================================================================726727def EquivariantMonoidPowerSeries( parent, coefficients, precision, symmetrise = False,728cleanup_coefficients = False) :729r"""730Create an equivariant monoid power series within a given parent.731732INPUT:733- ``parent`` -- A ring or module of equivariant monoid power series.734- ``coefficients`` -- A dictionary with keys in the parent's monoid and values735in the parent coefficient domain.736- ``precision`` -- A filter for the parent's action.737- ``symmetrise`` -- A boolean (default: ``False``); If ``True`` every enty in738``coefficients`` will contribute to its whole orbit.739- ``cleanup_coefficients`` -- A boolean (default: ``False``); If ``True`` zero740coefficients will be erased from the dictionary.741742OUTPUT:743An instance of :class:~`.EquivariantMonoidPowerSeries_abstract`.744745EXAMPLES::746sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *747sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *748sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *749sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *750sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )751sage: h = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().filter(3))752753TESTS::754sage: h = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().zero_filter(), True)755sage: h = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 4, 0 : 3}}, emps.action().filter_all())756sage: h = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 4, 0 : 3}}, emps.action().filter_all(), symmetrise = True)757sage: emps = EquivariantMonoidPowerSeriesModule( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", FreeModule(QQ, 2)) )758sage: h = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().filter(3))759"""760if isinstance(parent, Module) :761return EquivariantMonoidPowerSeries_moduleelement( parent, coefficients, precision, symmetrise,762cleanup_coefficients )763if isinstance(parent, Ring) :764return EquivariantMonoidPowerSeries_algebraelement( parent, coefficients, precision, symmetrise,765cleanup_coefficients )766767raise TypeError, "Unexpected type of parent"768769#===============================================================================770# EquivariantMonoidPowerSeries_abstract771#===============================================================================772773class EquivariantMonoidPowerSeries_abstract :774r"""775An abstract element of an equivariant monoid power series ring up to776given precision.777"""778779def __init__( self, parent, precision ) :780r"""781INPUT:782- ``parent`` -- A ring or module of equivariant monoid power series.783- ``precision`` -- A filter for the parent's action.784785TESTS::786sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *787sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *788sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *789sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )790sage: h = EquivariantMonoidPowerSeries_abstract(emps, emps.action().zero_filter()) # indirect doctest791"""792self.__precision = parent.action().filter(precision)793794def precision(self) :795r"""796The series' precision.797798OUTPUT:799A filter for the parent's action.800801TESTS::802sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *803sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *804sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *805sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )806sage: EquivariantMonoidPowerSeries_abstract(emps, emps.action().filter(3)).precision() == emps.action().filter(3)807True808"""809return self.__precision810811def _set_precision(self, precision) :812r"""813Set the series' precision.814815INPUT:816- ``precision`` -- A filter for the parent's action.817818TESTS::819sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *820sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *821sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *822sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )823sage: e = copy(emps.one_element())824sage: e._set_precision(emps.action().filter(3))825sage: e.precision() == emps.action().filter(3)826True827sage: e._set_precision(2)828sage: e.precision() == emps.action().filter(2)829True830"""831self.__precision = self.parent().action().filter(precision)832833def non_zero_components(self) :834r"""835Return all those characters which are not guaranteed to have only836vanishing coefficients associated to.837838OUTPUT:839A list of elements of the character monoid.840841NOTE:842The components associated to characters this function returns can vanish.843For exact results use ``_cleanup_coefficients(in_place = True)`` before.844845EXAMPLES::846sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *847sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *848sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *849sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )850sage: e = EquivariantMonoidPowerSeries(emps, dict(), emps.monoid().zero_filter())851sage: e.non_zero_components()852[]853sage: emps.one_element().non_zero_components()854[1]855"""856return list(self.parent().characters())857858def _bounding_precision(self) :859r"""860If ``self.precision()`` is an infinite filter, return a filter861which contains all non zero coefficients of this series. Otherwise,862return ``self.precision()``863864OUTPUT:865A filter for the parent's action.866867TESTS::868sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *869sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *870sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *871sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )872sage: e = EquivariantMonoidPowerSeries(emps, dict(), emps.action().filter(2))873sage: e._bounding_precision() == emps.action().filter(2)874True875sage: e = EquivariantMonoidPowerSeries(emps, dict(), emps.action().filter_all())876sage: e._bounding_precision() == emps.action().zero_filter()877True878"""879if not self.precision().is_infinite() :880return self.precision()881882coeffs = self.coefficients(True)883m = self.parent().action().zero_filter()884for c in self.non_zero_components() :885m = max(m, self.parent().action().minimal_composition_filter( coeffs[c].keys(),886[self.parent().action().zero_element()] ))887return m888889def coefficients(self, force_characters = False) :890r"""891The coefficients of ``self``.892893INPUT:894- ``force_characters`` -- A boolean (default: ``False``); If ``True`` the895the dictionary returned will have characters as keys896in any cases.897898OUTPUT:899Either of the following two:900- A dictionary with keys the elements of the parent's monoid and values in the901parent's coefficient domain.902- A dictionary with keys the parent's characters and values the a dictionary as follows. This903dictionary has keys the elements of the parent's monoid and values in the parent's904coefficient domain.905906EXAMPLES::907sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *908sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *909sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *910sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )911sage: EquivariantMonoidPowerSeries_abstract(emps, emps.action().zero_filter()).coefficients()912Traceback (most recent call last):913...914NotImplementedError915"""916raise NotImplementedError917918def _truncate_in_place(self, precision) :919r"""920Truncate ``self`` modifying the coefficient dictionary directly.921922INPUT:923- ``precision`` -- A filter for the parent's monoid or a an object that can be converted924to a filter.925926OUTPUT:927``None``928929TESTS::930sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *931sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *932sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *933sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )934sage: e = emps.one_element()935sage: EquivariantMonoidPowerSeries_abstract(emps, emps.action().filter_all())._truncate_in_place(emps.monoid().zero_filter())936Traceback (most recent call last):937...938NotImplementedError939"""940raise NotImplementedError941942def truncate(self, precision) :943r"""944Truncate a copy of ``self``.945946INPUT:947- ``precision`` -- A filter for the parent's monoid or a an object that can be converted948to a filter.949950OUTPUT:951An instance of :class:~`.EquivariantMonoidPowerSeries_abstract`.952953TESTS::954sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *955sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *956sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *957sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )958sage: EquivariantMonoidPowerSeries_abstract(emps, emps.action().filter_all()).truncate(emps.action().zero_filter())959Traceback (most recent call last):960...961NotImplementedError962"""963raise NotImplementedError964965def _add_(left, right) :966r"""967TESTS::968sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *969sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *970sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *971sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )972sage: e = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 1 : 1 }}, emps.action().filter_all())973sage: (e + e)[1]9742975"""976prec = min(left.precision(), right.precision())977978left_coefficients = left.coefficients(True)979right_coefficients = right.coefficients(True)980981left_characters = set(left_coefficients)982right_characters = set(right_coefficients)983coefficients = dict()984985for ch in left_characters - right_characters :986coefficients[ch] = copy(left_coefficients[ch])987for ch in right_characters - left_characters :988coefficients[ch] = copy(right_coefficients[ch])989990for ch in left_characters.intersection(right_characters) :991lcoeffs = left_coefficients[ch]992rcoeffs = right_coefficients[ch]993994lcoeff_keys = set(lcoeffs)995rcoeff_keys = set(rcoeffs)996997nd = dict()998for k in lcoeff_keys - rcoeff_keys :999nd[k] = lcoeffs[k]1000for k in rcoeff_keys - lcoeff_keys :1001nd[k] = rcoeffs[k]1002for k in lcoeff_keys.intersection(rcoeff_keys) :1003nd[k] = lcoeffs[k] + rcoeffs[k]10041005coefficients[ch] = nd10061007return EquivariantMonoidPowerSeries(left.parent(),1008coefficients, prec)10091010def _mul_(left, right, switch_factors = False) :1011r"""1012TESTS::1013sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1014sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1015sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1016sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1017sage: e = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 1 : 1 }}, emps.action().filter_all())1018sage: (e * e)[2]101911020"""1021mul_fc = left.parent()._multiply_function()1022coefficient_domain = left.parent().coefficient_domain()10231024prec = min(left.precision(), right.precision())1025if not switch_factors :1026left_coefficients = left.coefficients(True)1027right_coefficients = right.coefficients(True)1028else :1029right_coefficients = left.coefficients(True)1030left_coefficients = right.coefficients(True)10311032if prec.is_infinite() :1033left_keys = reduce(union, (set(left_coefficients[c]) for c in left_coefficients), set())1034right_keys = reduce(union, (set(right_coefficients[c]) for c in right_coefficients), set())10351036if len(left_keys) == 0 or len(right_keys) == 0:1037return EquivariantMonoidPowerSeries(left.parent(), dict(), prec)1038iter_prec = left.parent().action(). \1039minimal_composition_filter(left_keys, right_keys)1040else :1041iter_prec = prec10421043coefficients = dict()1044for c1 in left_coefficients :1045lcoeffs = left_coefficients[c1]1046if len(lcoeffs) == 0 : continue10471048for c2 in right_coefficients :1049rcoeffs = right_coefficients[c2]1050if len(rcoeffs) == 0 : continue10511052try :1053d = coefficients[c1 * c2]1054except KeyError :1055d = dict()1056coefficients[c1 * c2] = d10571058for k in iter_prec :1059v = mul_fc( k, lcoeffs, rcoeffs, c1, c2, coefficient_domain(0) )10601061if not v.is_zero() :1062try :1063d[k] += v1064if d[k].is_zero() :1065del d[k]1066except KeyError :1067d[k] = v10681069return EquivariantMonoidPowerSeries( left.parent(), coefficients, prec )10701071def _lmul_(self, c) :1072r"""1073TESTS::1074sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1075sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1076sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *1077sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1078sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1079sage: (emps.one_element() * 2) * 3 == emps.one_element() * 61080True1081sage: m = FreeModule(QQ, 3)1082sage: empsm = EquivariantMonoidPowerSeriesModule(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", m))1083sage: h = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element(): {1: 1, 3: 2}}, emps.action().filter_all())1084sage: hv = EquivariantMonoidPowerSeries(empsm, {empsm.characters().one_element(): {1: m([1,0,0]), 2: m([0,0,1])}}, empsm.action().filter_all())1085sage: hh = hv * h1086"""1087if c.is_zero() :1088return EquivariantMonoidPowerSeries(self.parent(), dict(), self.parent().monoid().filter_all())10891090if isinstance(c, EquivariantMonoidPowerSeries_abstract) and not isinstance(self, AlgebraElement) :1091nzc = c.non_zero_components()1092if len(nzc) == 1 :1093coeffs = c.coefficients(True)[nzc[0]]10941095if len(coeffs) == 1 and self.parent().action().zero_element() in coeffs :1096c = coeffs[self.parent().action().zero_element()]10971098self_coefficients = self.coefficients(True)1099coefficients = dict()1100for ch in self_coefficients :1101coefficients[ch] = dict((k, c*v) for (k,v) in self_coefficients[ch].iteritems())11021103return EquivariantMonoidPowerSeries(self.parent(),1104coefficients, self.precision())11051106return self._mul_(c, False)1107else :1108self_coefficients = self.coefficients(True)1109coefficients = dict()1110for ch in self_coefficients :1111coefficients[ch] = dict((k, c*v) for (k,v) in self_coefficients[ch].iteritems())11121113return EquivariantMonoidPowerSeries(self.parent(),1114coefficients, self.precision())11151116def _rmul_(self, c) :1117r"""1118TESTS::1119sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1120sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1121sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *1122sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1123sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1124sage: 3 * (2 * emps.one_element()) == 6 * emps.one_element()1125True1126sage: m = FreeModule(QQ, 3)1127sage: empsm = EquivariantMonoidPowerSeriesModule(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", m))1128sage: h = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element(): {1: 1, 3: 2}}, emps.action().filter_all())1129sage: hv = EquivariantMonoidPowerSeries(empsm, {empsm.characters().one_element(): {1: m([1,0,0]), 2: m([0,0,1])}}, empsm.action().filter_all())1130sage: hh = h * hv1131"""1132if c.is_zero() :1133return EquivariantMonoidPowerSeries(self.parent(), dict(), self.parent().monoid().filter_all())11341135if isinstance(c, EquivariantMonoidPowerSeries_abstract) and not isinstance(self, AlgebraElement) :1136nzc = c.non_zero_components()1137if len(nzc) == 1 :1138coeffs = c.coefficients(True)[nzc[0]]11391140if len(coeffs) == 1 and self.parent().action().zero_element() in coeffs :1141c = coeffs[self.parent().action().zero_element()]11421143self_coefficients = self.coefficients(True)1144coefficients = dict()1145for ch in self_coefficients :1146coefficients[ch] = dict((k, v*c) for (k,v) in self_coefficients[ch].iteritems())11471148return EquivariantMonoidPowerSeries(self.parent(),1149coefficients, self.precision())11501151return self._mul_(c, True)1152else :1153self_coefficients = self.coefficients(True)1154coefficients = dict()1155for ch in self_coefficients :1156coefficients[ch] = dict((k, v*c) for (k,v) in self_coefficients[ch].iteritems())11571158return EquivariantMonoidPowerSeries(self.parent(),1159coefficients, self.precision())11601161def __contains__(self, k) :1162r"""1163Check whether an index or a pair of character and index1164is containted in the precision.11651166EXAMPLES:1167sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1168sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1169sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1170sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1171sage: e = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 1, 2 : 1}}, emps.action().filter(3))1172sage: 3 in e1173False1174sage: 2 in e1175True1176sage: (emps.characters().one_element(),2) in e1177True1178"""1179try :1180(ch, k) = k1181if k not in self.parent().monoid() :1182k = (ch, k)1183except TypeError :1184pass11851186return k in self.precision()11871188def __getitem__(self, k) :1189r"""1190Return the `k`-th coefficient if it below the series' precision. If no character is contained1191in the key ``self`` must have only one nonvanishing component.11921193INPUT:1194- `k` -- A pair of an element of the parent's character monoid and1195and element of the parent's monoid or an element of the parent's monoid.11961197OUTPUT:1198An element of the parent's coefficient domain.11991200TESTS::1201sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1202sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1203sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1204sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1205sage: EquivariantMonoidPowerSeries_abstract(emps, emps.action().filter_all())[(emps.characters().one_element(), 0)]1206Traceback (most recent call last):1207...1208NotImplementedError1209"""1210raise NotImplementedError12111212def __cmp__(self, other) :1213r"""1214TESTS::1215sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1216sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1217sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1218sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1219sage: e = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 1 : 1 }}, emps.action().zero_filter())1220sage: e == EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 1 : 1 }}, emps.action().zero_filter())1221True1222sage: e == 2 * e1223False1224sage: e == EquivariantMonoidPowerSeries(emps, {}, emps.action().zero_filter())1225False1226"""1227c = cmp(self.precision(), other.precision())1228if c != 0 : return c12291230self_coefficients = self.coefficients(True)1231other_coefficients = other.coefficients(True)1232for ch in set(self_coefficients) - set(other_coefficients) :1233d = self_coefficients[ch]1234for k in d:1235if not d[k] == 0 :1236return -11237for ch in set(other_coefficients) - set(self_coefficients) :1238d = other_coefficients[ch]1239for k in d:1240if not d[k] == 0 :1241return -112421243for ch in set(self_coefficients).intersection(set(other_coefficients)) :1244s = self_coefficients[ch]1245o = other_coefficients[ch]1246self_keys = set(s)1247other_keys = set(o)12481249for k in self_keys - other_keys :1250if not s[k] == 0 :1251return -11252for k in other_keys - self_keys :1253if not o[k] == 0 :1254return -112551256for k in self_keys.intersection(other_keys) :1257if s[k] != o[k] :1258return -112591260return 012611262def _repr_(self) :1263r"""1264TESTS::1265sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1266sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1267sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1268sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1269sage: EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 1 : 1 }}, emps.action().zero_filter())1270Equivariant monoid power series in Ring of equivariant monoid power series over NN1271"""1272return "Equivariant monoid power series in %s" % (self.parent(),)12731274def _latex_(self) :1275r"""1276EXAMPLES:1277sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1278sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1279sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1280sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1281sage: latex( EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 1 : 1 }}, emps.action().zero_filter()) )1282\text{Equivariant monoid power series in }\text{Ring of equivariant monoid power series over }\Bold{N}1283"""1284return r"\text{Equivariant monoid power series in }%s" % latex(self.parent())12851286#===============================================================================1287# EquivariantMonoidPowerSeries_abstract_nonlazy1288#===============================================================================12891290class EquivariantMonoidPowerSeries_abstract_nonlazy ( EquivariantMonoidPowerSeries_abstract ) :1291r"""1292A abstract implementation of equiavariant monoid power series that store their coefficients.1293"""12941295def __init__( self, parent, coefficients, precision, symmetrise,1296cleanup_coefficients ) :1297r"""1298INPUT:1299- ``parent`` -- A ring or module of equivariant monoid power series.1300- ``coefficients`` -- A dictionary with keys in the parent's monoid and values1301in the parent coefficient domain.1302- ``precision`` -- A filter for the parent's action.1303- ``symmetrise`` -- A boolean (default: ``False``); If ``True`` every enty in1304``coefficients`` will contribute to its whole orbit.1305- ``cleanup_coefficients`` -- A boolean (default: ``False``); If ``True`` zero1306coefficients will be erased from the dictionary.13071308TESTS::1309sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1310sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1311sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *1312sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1313sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1314sage: h = EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().filter(3), False, False)1315sage: h = EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().zero_filter(), False, True)1316sage: h = EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 4, 0 : 3}}, emps.action().filter_all(), False, False,)1317sage: h = EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 4, 0 : 3}}, emps.action().filter_all(), True, False)1318sage: emps = EquivariantMonoidPowerSeriesModule( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", FreeModule(QQ, 2)) )1319sage: h = EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().filter(3), False, False)1320"""1321EquivariantMonoidPowerSeries_abstract.__init__(self, parent, precision)13221323if cleanup_coefficients and len(coefficients) != 0 :1324ncoefficients = self._cleanup_coefficients( coefficients,1325in_place = True )1326else :1327ncoefficients = coefficients13281329if symmetrise :1330## for symmetrisation we are guaranteed that1331## the representation acts trivially on all coefficients1332reduction = parent._reduction_function()1333character_eval = parent._character_eval_function()13341335self.__coefficients = dict()13361337for ch in ncoefficients :1338d = ncoefficients[ch]1339nd = dict()1340self.__coefficients[ch] = nd13411342for s in d :1343rs, g = reduction(s)1344try :1345nd[rs] += character_eval(g, ch) * d[s]1346except KeyError :1347nd[rs] = character_eval(g, ch) * d[s]1348else :1349self.__coefficients = ncoefficients13501351def non_zero_components(self) :1352r"""1353Return all those characters which are not guaranteed to have only1354vanishing coefficients associated to.13551356OUTPUT:1357A list of elements of the character monoid.13581359NOTE:1360The components associated to characters this function returns can vanish.1361For exact results use ``_cleanup_coefficients(in_place = True)`` before.13621363EXAMPLES::1364sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1365sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1366sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1367sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1368sage: e = EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 0}}, emps.action().zero_filter(), False, False)1369sage: e.non_zero_components()1370[1]1371sage: e._cleanup_coefficients(in_place = True)1372{}1373sage: e.non_zero_components()1374[]1375"""1376return self.__coefficients.keys()13771378def coefficients(self, force_characters = False) :1379r"""1380The coefficients of ``self``.13811382INPUT:1383- ``force_characters`` -- A boolean (default: ``False``); If ``True`` the1384the dictionary returned will have characters as keys1385in any cases.13861387OUTPUT:1388Either of the following two:1389- A dictionary with keys the elements of the parent's monoid and values in the1390parent's coefficient domain.1391- A dictionary with keys the parent's characters and values the a dictionary as follows. This1392dictionary has keys the elements of the parent's monoid and values in the parent's1393coefficient domain.13941395NOTE:1396Some keys may be invalid. To get an exact result1397call ``_cleanup_coefficients(in_place = True)`` before.13981399EXAMPLES::1400sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1401sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1402sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1403sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1404sage: EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().zero_filter(), False, False).coefficients()1405{1: 1}1406sage: EquivariantMonoidPowerSeries_abstract_nonlazy(emps, {emps.characters().one_element() : {1 : 1}}, emps.action().zero_filter(), False, False).coefficients(True)1407{1: {1: 1}}1408"""1409if len(self.__coefficients) == 0 :1410return dict()1411elif not force_characters and len(self.__coefficients) == 1 :1412return self.__coefficients.values()[0]1413else :1414return self.__coefficients14151416def _cleanup_coefficients(self, coefficients = None, in_place = True) :1417r"""1418Remove zero entries and entries not below ``self.precision()`` from a coefficient dictionary.14191420INPUT:1421- ``coefficients`` -- ``None`` or a dictionary (default: ``None``); If ``None`` the1422coefficient dictionary assigned to ``self`` will be cleaned.1423- ``in_place`` -- A boolean (default: ``True``); If ``False`` a copy of the coefficient1424dictionary will me cleaned and returned.14251426OUTPUT:1427A dictionary with keys the parent's characters and values the a dictionary as follows. This1428dictionary has keys the elements of the parent's monoid and values in the parent's1429coefficient domain.14301431TESTS::1432sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1433sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1434sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1435sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1436sage: emps.one_element()._cleanup_coefficients()1437{1: {0: 1}}1438sage: d = {emps.characters().one_element() : {1 : 1}}1439sage: tmp = EquivariantMonoidPowerSeries(emps, dict(), emps.action().zero_filter())._cleanup_coefficients(d)1440sage: d1441{}1442sage: emps.zero_element()._cleanup_coefficients({emps.characters().one_element() : {1 : 0}}, False)1443{}1444sage: h = copy(emps.one_element())1445sage: h._set_precision(emps.action().zero_filter())1446sage: h._cleanup_coefficients(in_place = False)1447{}1448"""1449if coefficients is None :1450coefficients = self.__coefficients14511452if not in_place :1453ncoefficients = dict()14541455for ch in coefficients.keys() :1456d = coefficients[ch]14571458if in_place :1459for s in d.keys() :1460if not s in self.precision() or d[s].is_zero() :1461del d[s]14621463if len(d) == 0 :1464del coefficients[ch]1465else :1466nd = dict()14671468for s in d :1469if not s in self.precision() : continue14701471v = d[s]1472if v.is_zero() : continue14731474nd[s] = v14751476if len(nd) != 0 :1477ncoefficients[ch] = nd14781479if in_place :1480return coefficients1481else :1482return ncoefficients14831484def _truncate_in_place(self, precision) :1485r"""1486Truncate ``self`` modifying the coefficient dictionary directly.14871488INPUT:1489- ``precision`` -- A filter for the parent's monoid or a an object that can be converted1490to a filter.14911492OUTPUT:1493``None``14941495TESTS::1496sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1497sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1498sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1499sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1500sage: e = copy(emps.one_element())1501sage: e._truncate_in_place(emps.monoid().zero_filter())1502sage: e.coefficients()1503{}1504sage: e = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 1, 2 : 0}}, emps.action().filter(3))1505sage: e._truncate_in_place(2)1506sage: 2 in e.coefficients()1507False1508"""1509precision = self.parent().action().filter(precision)1510nprec = min(self.precision(), precision)15111512if nprec != self.precision() :1513for c in self.__coefficients :1514d = self.__coefficients[c]1515for k in d.keys() :1516if not k in nprec :1517del d[k]15181519self._set_precision(nprec)15201521def truncate(self, precision) :1522r"""1523Truncate a copy of ``self``.15241525INPUT:1526- ``precision`` -- A filter for the parent's monoid or a an object that can be converted1527to a filter.15281529OUTPUT:1530An instance of :class:~`.EquivariantMonoidPowerSeries_abstract`.15311532TESTS::1533sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1534sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1535sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1536sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1537sage: emps.one_element().truncate(emps.monoid().zero_filter()).coefficients()1538{}1539sage: e = EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : {1 : 1, 2 : 0}}, emps.action().filter(3))1540sage: 2 in e.truncate(2)1541False1542"""1543precision = self.parent().action().filter(precision)1544nprec = min(self.precision(), precision)15451546ncoefficients = dict( (ch, copy(self.__coefficients[ch]))1547for ch in self.__coefficients )1548return EquivariantMonoidPowerSeries( self.parent(),1549ncoefficients, nprec, cleanup_coefficients = True )15501551def __getitem__(self, k) :1552r"""1553Return the `k`-th coefficient if it below the series' precision. If no character is contained1554in the key ``self`` must have only one nonvanishing component.15551556INPUT:1557- `k` -- A pair of an element of the parent's character monoid and1558and element of the parent's monoid or an element of the parent's monoid.15591560OUTPUT:1561An element of the parent's coefficient domain.15621563TESTS::1564sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1565sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1566sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1567sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1568sage: EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 0 : 10, 1 : 1 }}, emps.action().filter_all())[(emps.characters().one_element(), 0)]1569101570sage: EquivariantMonoidPowerSeries(emps, {emps.characters().one_element() : { 0 : 10, 1 : 1 }}, emps.action().filter_all())[1]157111572"""1573try :1574if not isinstance(k, tuple) :1575raise ValueError15761577(ch, k) = k1578if k not in self.parent().monoid() :1579s = (ch, k)1580ch = None1581else :1582s = k1583except ValueError :1584s = k1585ch = None15861587try :1588if not ch.parent() == self.parent().characters() :1589ch = None1590except AttributeError :1591ch = None15921593if ch is None :1594ns = self.non_zero_components()1595if len(ns) == 0 :1596return 01597elif len(ns) == 1 :1598ch = ns[0]1599else :1600raise ValueError, "you must specify a character"16011602if not s in self.precision() :1603raise ValueError, "%s out of bound" % (s,)16041605try :1606return self.__coefficients[ch][s]1607except KeyError :1608(rs, g) = self.parent()._reduction_function()(s)16091610try :1611return self.parent()._character_eval_function()(g, ch) \1612* self.parent()._apply_function()(g, self.__coefficients[ch][rs])1613except KeyError :1614return self.parent().coefficient_domain().zero_element()16151616#===============================================================================1617# EquivariantMonoidPowerSeries_moduleelement1618#===============================================================================16191620class EquivariantMonoidPowerSeries_moduleelement ( EquivariantMonoidPowerSeries_abstract_nonlazy, ModuleElement ) :1621r"""1622An element of a module of equivariant monoid power series.1623"""16241625def __init__(self, parent, coefficients, precision, symmetrise,1626cleanup_coefficients ) :1627r"""1628INPUT:1629- ``parent`` -- A ring or module of equivariant monoid power series.1630- ``coefficients`` -- A dictionary with keys in the parent's monoid and values1631in the parent coefficient domain.1632- ``precision`` -- A filter for the parent's action.1633- ``symmetrise`` -- A boolean (default: ``False``); If ``True`` every enty in1634``coefficients`` will contribute to its whole orbit.1635- ``cleanup_coefficients`` -- A boolean (default: ``False``); If ``True`` zero1636coefficients will be erased from the dictionary.16371638TESTS::1639sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1640sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *1641sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1642sage: emps = EquivariantMonoidPowerSeriesModule( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", FreeModule(QQ, 2)) )1643sage: h = EquivariantMonoidPowerSeries_moduleelement(emps, dict(), emps.action().zero_filter(), False, False)1644"""1645ModuleElement.__init__(self, parent)1646EquivariantMonoidPowerSeries_abstract_nonlazy.__init__(self, parent, coefficients, precision, symmetrise,1647cleanup_coefficients)16481649#===============================================================================1650# EquivariantMonoidPowerSeries_algebraelement1651#===============================================================================16521653class EquivariantMonoidPowerSeries_algebraelement ( EquivariantMonoidPowerSeries_abstract_nonlazy, AlgebraElement ) :1654r"""1655An element of an algebra of equivariant monoid power series.1656"""16571658def __init__(self, parent, coefficients, precision, symmetrise,1659cleanup_coefficients ) :1660r"""1661INPUT:1662- ``parent`` -- A ring or module of equivariant monoid power series.1663- ``coefficients`` -- A dictionary with keys in the parent's monoid and values1664in the parent coefficient domain.1665- ``precision`` -- A filter for the parent's action.1666- ``symmetrise`` -- A boolean (default: ``False``); If ``True`` every enty in1667``coefficients`` will contribute to its whole orbit.1668- ``cleanup_coefficients`` -- A boolean (default: ``False``); If ``True`` zero1669coefficients will be erased from the dictionary.16701671TESTS::1672sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *1673sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *1674sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *1675sage: emps = EquivariantMonoidPowerSeriesRing( NNMonoid(), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ) )1676sage: h = EquivariantMonoidPowerSeries_algebraelement(emps, dict(), emps.action().zero_filter(), False, False)1677"""1678AlgebraElement.__init__(self, parent)1679EquivariantMonoidPowerSeries_abstract_nonlazy.__init__(self, parent, coefficients, precision, symmetrise,1680cleanup_coefficients)168116821683