Ticket #9651: trac_9651_CombinatorialFreeModule_Addition-cs.4.patch

File trac_9651_CombinatorialFreeModule_Addition-cs.4.patch, 26.3 KB (added by stumpc5, 11 years ago)

includes more referees suggestions

  • module_list.py

    # HG changeset patch
    # User Christian Stump <christian.stump@univie.ac.at>
    # Date 1281041363 25200
    # Node ID 4e32b2a6222d9c27fcbdd9308b9954b2e572b491
    # Parent  8a631e73ed0b24061f915394c1403e0832b18f64
    * * *
    Trac 9651: Improved speed for CombinatorialFreeModule
    
    diff --git a/module_list.py b/module_list.py
    a b ext_modules = [ 
    203203    Extension('sage.combinat.permutation_cython',
    204204              sources=['sage/combinat/permutation_cython.pyx']),
    205205
     206    Extension('sage.combinat.dict_addition',
     207              sources=['sage/combinat/dict_addition.pyx']),
     208
    206209    ################################
    207210    ##
    208211    ## sage.crypto
  • sage/categories/algebras_with_basis.py

    diff --git a/sage/categories/algebras_with_basis.py b/sage/categories/algebras_with_basis.py
    a b class AlgebrasWithBasis(Category_over_ba 
    5353        B[word: acb]
    5454
    5555        sage: A.product
    56         Generic endomorphism of An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field
     56        <bound method FreeAlgebra_with_category._product_from_product_on_basis_multiply of An example of an algebra with basis: the free algebra on the generators ('a', 'b', 'c') over Rational Field>
    5757        sage: A.product(a*b,b)
    5858        B[word: abb]
    5959
    class AlgebrasWithBasis(Category_over_ba 
    272272                3*B[word: ac] + 6*B[word: bc]
    273273            """
    274274            if self.product_on_basis is not NotImplemented:
    275                 return self._module_morphism(self._module_morphism(self.product_on_basis, position = 0, codomain=self),
    276                                                                                           position = 1)
     275                return self._product_from_product_on_basis_multiply
     276#                return self._module_morphism(self._module_morphism(self.product_on_basis, position = 0, codomain=self),
     277#                                                                                          position = 1)
    277278            elif hasattr(self, "_multiply") or hasattr(self, "_multiply_basis"):
    278279                return self._product_from_combinatorial_algebra_multiply
    279280            else:
    280281                return NotImplemented
    281282
     283        # Provides a product using the product_on_basis by calling linear_combination only once
     284        def _product_from_product_on_basis_multiply( self, left, right ):
     285            return self.linear_combination( ( self.product_on_basis( mon_left, mon_right ), coeff_left * coeff_right ) for ( mon_left, coeff_left ) in left.monomial_coefficients().iteritems() for ( mon_right, coeff_right ) in right.monomial_coefficients().iteritems() )
     286
    282287        # Backward compatibility temporary cruft to help migrating form CombinatorialAlgebra
    283288        def _product_from_combinatorial_algebra_multiply(self,left,right):
    284289            """
  • sage/categories/hopf_algebras_with_basis.py

    diff --git a/sage/categories/hopf_algebras_with_basis.py b/sage/categories/hopf_algebras_with_basis.py
    a b class HopfAlgebrasWithBasis(Category_ove 
    5555        B[(1,2)]
    5656
    5757        sage: A.product           # todo: not quite ...
    58         Generic endomorphism of A
     58        <bound method MyGroupAlgebra_with_category._product_from_product_on_basis_multiply of A>
    5959        sage: A.product(b,b)
    6060        B[()]
    6161
  • sage/categories/modules_with_basis.py

    diff --git a/sage/categories/modules_with_basis.py b/sage/categories/modules_with_basis.py
    a b class ModuleMorphismByLinearity(Morphism 
    12481248        assert(x.parent() is self.domain())
    12491249
    12501250        if self._is_module_with_basis_over_same_base_ring:
    1251             return self.codomain().sum(self._on_basis(*(before+(index,)+after))._lmul_(coeff) for (index, coeff) in args[self._position])
     1251            return self.codomain().linear_combination( (self._on_basis(*(before+(index,)+after)), coeff ) for (index, coeff) in args[self._position] )
    12521252        else:
    12531253            return sum(( coeff * self._on_basis(*(before+(index,)+after)) for (index, coeff) in args[self._position]), self._zero)
    12541254
  • new file sage/combinat/dict_addition.pyx

    diff --git a/sage/combinat/dict_addition.pyx b/sage/combinat/dict_addition.pyx
    new file mode 100644
    - +  
     1"""
     2Provides function to add dictionaries pointwise with values in a common ring and to compute linear combinations
     3"""
     4#*****************************************************************************
     5#       Copyright (C) 2010 Christian Stump christian.stump@univie.ac.at
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#                  http://www.gnu.org/licenses/
     9#*****************************************************************************
     10
     11def dict_addition( dict_iter ):
     12    """
     13    returns the pointwise addition of dictionaries with coefficients
     14   
     15    INPUT:
     16        dict_iter         -- iterator of dictionaries with values in a common ring R
     17       
     18    OUTPUT:
     19        dictionary containing all keys of dictionaries in dict_list (and non-zero values) being the the sum of the values in the different
     20        dictionaries
     21   
     22    EXAMPLES:
     23        sage: from sage.combinat.dict_addition import dict_addition
     24        sage: D = { 0:1, 1:1 }; D
     25        {0: 1, 1: 1}
     26        sage: dict_addition( D for _ in range(5) )
     27        {0: 5, 1: 5}
     28    """
     29    cdef dict D, D_tmp
     30
     31    D = {}
     32    for D_tmp in dict_iter:
     33        if D == {}:
     34            D = D_tmp.copy()
     35        else:   
     36            for key, value in D_tmp.iteritems():
     37                if key in D:
     38                    D[ key ] += value
     39                else:
     40                    D[ key ]  = value
     41
     42    for_removal = [ key for key, value in D.iteritems() if value == 0 ]
     43    for key in for_removal:
     44        del D[key]   
     45
     46    return D
     47
     48def dict_linear_combination( dict_factor_iter, factor_on_left=True ):
     49    """
     50    returns the pointwise addition of dictionaries with coefficients
     51   
     52    INPUT:
     53        dict_factor_iter            -- iterator of pairs D, coeff, where
     54                                        the D's are dictionaries with values in a common ring R
     55                                        the coeff's are coefficients in R
     56        factor_on_left(optional)    -- if True, the coefficients are multiplied on the left, otherwise they are multiplied on the right
     57       
     58    OUTPUT:
     59        dictionary containing all keys of dictionaries in dict_list (and non-zero values) being the the sum of the values in the different
     60        dictionaries each one first multiplied by the given factor
     61   
     62    EXAMPLES:
     63        sage: from sage.combinat.dict_addition import dict_linear_combination
     64        sage: D = { 0:1, 1:1 }; D
     65        {0: 1, 1: 1}
     66        sage: dict_linear_combination( (D,i) for i in range(5) )
     67        {0: 10, 1: 10}
     68        sage: dict_linear_combination( [(D,1),(D,-1)] )
     69        {}
     70    """
     71    D = {}
     72    for D_tmp, fac_tmp in dict_factor_iter:
     73        if D == {} and fac_tmp == 1:
     74            D = D_tmp.copy()
     75        elif fac_tmp == 1:
     76            for key, value in D_tmp.iteritems():
     77                if key in D:
     78                    D[ key ] += value
     79                else:
     80                    D[ key ]  = value
     81        elif fac_tmp == -1:
     82            for key, value in D_tmp.iteritems():
     83                if key in D:
     84                    D[ key ]  -= value
     85                else:
     86                    D[ key ]   = -value
     87        else:
     88            if factor_on_left:
     89                for key, value in D_tmp.iteritems():
     90                    if key in D:
     91                        D[ key ] += fac_tmp * value
     92                    else:
     93                        D[ key ]  = fac_tmp * value
     94            else:
     95                for key, value in D_tmp.iteritems():
     96                    if key in D:
     97                        D[ key ] += value * fac_tmp
     98                    else:
     99                        D[ key ]  = value * fac_tmp
     100
     101    for_removal = [ key for key, value in D.iteritems() if value == 0 ]
     102    for key in for_removal:
     103        del D[key]   
     104
     105    return D
  • sage/combinat/free_module.py

    diff --git a/sage/combinat/free_module.py b/sage/combinat/free_module.py
    a b Free modules 
    44#*****************************************************************************
    55#       Copyright (C) 2007      Mike Hansen <mhansen@gmail.com>,
    66#                     2007-2009 Nicolas M. Thiery <nthiery at users.sf.net>
     7#                     2010      Christian Stump <christian.stump@univie.ac.at>
    78#
    89#  Distributed under the terms of the GNU General Public License (GPL)
    910#                  http://www.gnu.org/licenses/
    import sage.structure.element 
    2021from sage.combinat.family import Family
    2122from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
    2223from sage.combinat.cartesian_product import CartesianProduct
    23 from sage.categories.all import ModulesWithBasis
    2424from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets
    2525from sage.misc.cachefunc import cached_method
    2626from sage.misc.all import lazy_attribute
    2727from sage.categories.poor_man_map import PoorManMap
     28from sage.categories.all import ModulesWithBasis
     29from sage.combinat.dict_addition import dict_addition, dict_linear_combination
    2830
    2931# TODO: move the content of this class to CombinatorialFreeModule.Element and ModulesWithBasis.Element
    3032class CombinatorialFreeModuleElement(Element):
    class CombinatorialFreeModuleElement(Ele 
    196198        w.sort()
    197199        return cmp(v, w)
    198200
    199     def _add_(self, y):
     201    def _add_(self, other):
    200202        """
    201203        EXAMPLES::
    202204
    class CombinatorialFreeModuleElement(Ele 
    214216            sage: len(a.monomial_coefficients())
    215217            1
    216218        """
    217         A = self.parent()
    218         BR = A.base_ring()
    219         z_elt = dict(self._monomial_coefficients)
    220         for m, c in y._monomial_coefficients.iteritems():
    221             if z_elt.has_key(m):
    222                 cm = z_elt[m] + c
    223                 if cm == 0:
    224                     del z_elt[m]
    225                 else:
    226                     z_elt[m] = cm
    227             else:
    228                 z_elt[m] = c
    229219
     220        assert hasattr( other, 'parent' ) and other.parent() == self.parent()
    230221
    231         #Remove all entries that are equal to 0
    232         del_list = []
    233         zero = BR(0)
    234         for m, c in z_elt.iteritems():
    235             if c == zero:
    236                 del_list.append(m)
    237         for m in del_list:
    238             del z_elt[m]
    239 
    240         return A._from_dict(z_elt)
    241 
     222        F = self.parent()
     223        return F._from_dict( dict_addition( [ self._monomial_coefficients, other._monomial_coefficients ] ), remove_zeros=False )
    242224
    243225    def _neg_(self):
    244226        """
    class CombinatorialFreeModuleElement(Ele 
    256238            sage: -s([2,1]) # indirect doctest
    257239            -s[2, 1]
    258240        """
    259         return self.map_coefficients(lambda c: -c)
     241        F = self.parent()
     242        return F._from_dict( dict_linear_combination( [ ( self._monomial_coefficients, -1 ) ] ), remove_zeros=False )
    260243
    261 
    262     def _sub_(self, y):
     244    def _sub_(self, other):
    263245        """
    264246        EXAMPLES::
    265247
    class CombinatorialFreeModuleElement(Ele 
    274256            sage: s([2,1]) - s([5,4]) # indirect doctest
    275257            s[2, 1] - s[5, 4]
    276258        """
    277         A = self.parent()
    278         BR = A.base_ring()
    279         z_elt = dict(self._monomial_coefficients)
    280         for m, c in y._monomial_coefficients.iteritems():
    281             if z_elt.has_key(m):
    282                 cm = z_elt[m] - c
    283                 if cm == 0:
    284                     del z_elt[m]
    285                 else:
    286                     z_elt[m] = cm
    287             else:
    288                 z_elt[m] = -c
    289 
    290         #Remove all entries that are equal to 0
    291         zero = BR(0)
    292         del_list = []
    293         for m, c in z_elt.iteritems():
    294             if c == zero:
    295                 del_list.append(m)
    296         for m in del_list:
    297             del z_elt[m]
    298 
    299         return A._from_dict(z_elt)
    300 
     259        assert hasattr( other, 'parent' ) and other.parent() == self.parent()
     260        F = self.parent()
     261        return F._from_dict( dict_linear_combination( [ ( self._monomial_coefficients, 1 ), (other._monomial_coefficients, -1 ) ] ), remove_zeros=False )
    301262
    302263    def _coefficient_fast(self, m, default=None):
    303264        """
    class CombinatorialFreeModuleElement(Ele 
    401362            True
    402363        """
    403364        BR = self.parent().base_ring()
    404         return all(v == BR(0) for v in self._monomial_coefficients.values())
     365        zero = BR( 0 )
     366        return all( v == zero for v in self._monomial_coefficients.values() )
    405367
    406368    def __len__(self):
    407369        """
    class CombinatorialFreeModuleElement(Ele 
    445407            sage: z.length()
    446408            4
    447409        """
    448         return len([mon for mon,coeff in self._monomial_coefficients.items() if coeff !=0 ])
     410        BR = self.parent().base_ring()
     411        zero = BR( 0 )
     412        return len( [ key for key, coeff in self._monomial_coefficients.iteritems() if coeff != zero ] )
    449413
    450414    def support(self):
    451415        """
    class CombinatorialFreeModuleElement(Ele 
    467431            sage: z.support()
    468432            [[1], [1, 1, 1], [2, 1], [4]]
    469433        """
    470         v = self._monomial_coefficients.items()
    471         v.sort()
    472         mons = [ m for (m, _) in v ]
    473         # Usually we test the coeff for being non zero, why not here?
    474         # The same question arises in the following functions.
    475         return mons
     434        BR = self.parent().base_ring()
     435        zero = BR( 0 )
     436
     437        supp = [ key for key, coeff in self._monomial_coefficients.iteritems() if coeff != zero ]
     438        supp.sort()
     439       
     440        return supp
    476441
    477442    def monomials(self):
    478443        """
    class CombinatorialFreeModuleElement(Ele 
    485450            [B['a'], B['c']]
    486451        """
    487452        P = self.parent()
    488         one = P.base_ring()(1)
    489         v = self._monomial_coefficients.items()
    490         v.sort()
    491         return [P._from_dict({key:one}) for key,value in v]
     453        BR = P.base_ring()
     454        zero = BR( 0 )
     455        one = BR( 1 )
     456
     457        supp = [ key for key, coeff in self._monomial_coefficients.iteritems() if coeff != zero ]
     458        supp.sort()
     459       
     460        return [ P._from_dict( { key : one }, remove_zeros=False ) for key in supp ]
    492461
    493462    def terms(self):
    494463        """
    class CombinatorialFreeModuleElement(Ele 
    500469            sage: f.terms()
    501470            [B['a'], 2*B['c']]
    502471        """
    503         P = self.parent()
    504         v = self._monomial_coefficients.items()
     472        BR = self.parent().base_ring()
     473        zero = BR( 0 )
     474        v = [ ( key, value ) for key, value in self._monomial_coefficients.iteritems() if value != zero ]
    505475        v.sort()
    506         return [P._from_dict({key:value}) for key,value in v]
     476        from_dict = self.parent()._from_dict
     477        return [ from_dict( { key : value } ) for key,value in v ]
    507478
    508479    def coefficients(self):
    509480        """
    class CombinatorialFreeModuleElement(Ele 
    525496            sage: z.coefficients()
    526497            [1, 1, 1, 1]
    527498        """
    528         v = self._monomial_coefficients.items()
     499        BR = self.parent().base_ring()
     500        zero = BR( 0 )
     501        v = [ ( key, value ) for key, value in self._monomial_coefficients.iteritems() if value != zero ]
    529502        v.sort()
    530         cffs = [ c for (_, c) in v ]
    531         return cffs
     503        return [ value for key,value in v ]
    532504
    533505    def _vector_(self, new_base_ring=None):
    534506        """
    class CombinatorialFreeModuleElement(Ele 
    560532        if new_base_ring is None:
    561533            new_base_ring = parent.base_ring()
    562534        # FIXME: should return a sparse vector
    563         return vector(new_base_ring,
     535        return vector(new_base_ring, 
    564536                      [new_base_ring(self._monomial_coefficients.get(m, 0))
    565537                       for m in list(cc)])
    566538
    class CombinatorialFreeModuleElement(Ele 
    587559        """
    588560        return self._vector_()
    589561
    590 
    591 
    592562    def _acted_upon_(self, scalar, self_on_left = False):
    593563        """
    594564        Returns the action of a scalar on self
    class CombinatorialFreeModuleElement(Ele 
    649619        # enough information to detect apriori that this method only
    650620        # accepts scalars; so it tries on some elements(), and we need
    651621        # to make sure to report an error.
    652         if scalar.parent() != self.base_ring():
     622        if hasattr( scalar, 'parent' ) and scalar.parent() != self.base_ring():
    653623            # Temporary needed by coercion (see Polynomial/FractionField tests).
    654624            if self.base_ring().has_coerce_map_from(scalar.parent()):
    655                 scalar = self.base_ring()(scalar)
     625                scalar = self.base_ring()( scalar )
    656626            else:
    657627                return None
     628
     629        F = self.parent()
     630        D = self._monomial_coefficients
    658631        if self_on_left:
    659             return self.map_coefficients(lambda c: c*scalar)
     632            D = dict_linear_combination( [ ( D, scalar ) ], factor_on_left = False )
    660633        else:
    661             return self.map_coefficients(lambda c: scalar*c)
     634            D = dict_linear_combination( [ ( D, scalar ) ] )
     635
     636        return F._from_dict( D, remove_zeros=False )
    662637
    663638    # For backward compatibility
    664639    _lmul_ = _acted_upon_
    665640    _rmul_ = _acted_upon_
    666641
    667     def __div__(self, x):
     642    def __div__(self, x, self_on_left=False ):
    668643        """
    669644        Division by coefficients
    670645
    class CombinatorialFreeModuleElement(Ele 
    684659            B[2] + 2*B[3]
    685660        """
    686661        if self.base_ring().is_field():
    687             x = self.base_ring()(x)
    688             return self.map_coefficients(lambda c: c/x)
     662            F = self.parent()
     663            x = self.base_ring()( x )
     664            x_inv = x**-1
     665            D = self._monomial_coefficients
     666            if self_on_left:
     667                D = dict_linear_combination( [ ( D, x_inv ) ], factor_on_left=False )
     668            else:
     669                D = dict_linear_combination( [ ( D, x_inv ) ] )
     670
     671            return F._from_dict( D, remove_zeros=False )
    689672        else:
    690673            return self.map_coefficients(lambda c: _divide_if_possible(c, x))
    691674
    class CombinatorialFreeModule(UniqueRepr 
    831814        if R not in Rings():
    832815            raise TypeError, "Argument R must be a ring."
    833816        try:
    834             # R._one_element?
    835             z = R(Integer(1))
     817            z = R.one()
    836818        except:
    837819            raise ValueError, "R must have a unit element"
    838820
    class CombinatorialFreeModule(UniqueRepr 
    12831265        if c: return c
    12841266        return 0
    12851267
    1286     def _apply_module_morphism(self, x, f):
     1268    def _apply_module_morphism( self, x, on_basis, codomain=False ):
    12871269        """
    12881270        Returns the image of x under the module morphism defined by
    12891271        extending f by linearity.
    class CombinatorialFreeModule(UniqueRepr 
    12931275
    12941276        - ``x`` : a element of self
    12951277
    1296         - ``f``f - a function that takes in a combinatorial
     1278        - ``on_basis`` - a function that takes in a combinatorial
    12971279          object indexing a basis element and returns an element of the
    1298           target domain
     1280          codomain
     1281         
     1282        - ``codomain`` (optional) - the codomain of the morphism, otherwise it is computed using on_basis
    12991283
    13001284
    13011285        EXAMPLES::
    class CombinatorialFreeModule(UniqueRepr 
    13031287            sage: s = SFASchur(QQ)
    13041288            sage: a = s([3]) + s([2,1]) + s([1,1,1])
    13051289            sage: b = 2*a
    1306             sage: f = lambda part: len(part)
     1290            sage: f = lambda part: Integer( len(part) )
    13071291            sage: s._apply_module_morphism(a, f) #1+2+3
    13081292            6
    13091293            sage: s._apply_module_morphism(b, f) #2*(1+2+3)
    13101294            12
    13111295        """
    1312         res = 0
    1313         for m, c in x._monomial_coefficients.iteritems():
    1314             res += c*f(m)
    1315         return res
    13161296
     1297        if x == self.zero():
     1298            if not codomain:
     1299                B = self.basis()
     1300                keys = list( B.keys() )
     1301                if len( keys ) > 0:
     1302                    key = keys[0]
     1303                    codomain = on_basis( key ).parent()
     1304                else:
     1305                    raise ValueError, 'Codomain could not be determined'
    13171306
    1318     def _apply_module_endomorphism(self, a, f):
     1307            return codomain.zero()
     1308                   
     1309        else:
     1310            if not codomain:
     1311                keys = x.support()
     1312                key = keys[0]
     1313                codomain = on_basis( key ).parent()
     1314
     1315            if hasattr( codomain, 'linear_combination' ):
     1316                return codomain.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() )
     1317            else:
     1318                return_sum = codomain.zero()
     1319                for key, coeff in x._monomial_coefficients.iteritems():
     1320                    return_sum += coeff * on_basis( key )
     1321                return return_sum
     1322
     1323    def _apply_module_endomorphism(self, x, on_basis):
    13191324        """
    13201325        This takes in a function from the basis elements to the elements of
    13211326        self and applies it linearly to a. Note that
    class CombinatorialFreeModule(UniqueRepr 
    13291334            sage: s._apply_module_endomorphism( s([2,1]) + s([1,1,1]), f)
    13301335            2*s[2, 1] + 2*s[3]
    13311336        """
    1332         mcs = a.monomial_coefficients()
    1333         base_ring = self.base_ring()
    1334         zero = base_ring(0)
     1337        return self.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() )
    13351338
    1336         z_elt = {}
    1337         for basis_element in mcs:
    1338             f_mcs = f(basis_element).monomial_coefficients()
    1339             for f_basis_element in f_mcs:
    1340                 z_elt[ f_basis_element ] = z_elt.get(f_basis_element, zero) + mcs[basis_element]*f_mcs[f_basis_element]
     1339    def sum( self, iter_of_elements ):
     1340        """
     1341        overrides method inherited from commutative additive monoid as it is much faster on dicts directly
     1342       
     1343        INPUT:
     1344         - iter_of_elements: iterator of elements of self
    13411345
    1342         return self._from_dict(z_elt)
     1346        Returns the sum of all elements in iter_of_elements
     1347
     1348        EXAMPLES::
     1349            sage: F = CombinatorialFreeModule(QQ,[1,2])
     1350            sage: f = F.an_element(); f
     1351            2*B[1] + 2*B[2]
     1352            sage: F.sum( f for _ in range(5) )
     1353            10*B[1] + 10*B[2]
     1354        """
     1355   
     1356        D = dict_addition( element._monomial_coefficients for element in iter_of_elements )
     1357        return self._from_dict( D, remove_zeros=False )
     1358
     1359    def linear_combination( self, iter_of_elements_coeff, factor_on_left=True ):
     1360        """
     1361        INPUT:
     1362         - iter_of_elements_coeff   -- iterator of pairs ( element, coeff ) with element in self and coeff in self.base_ring()
     1363         - factor_on_left (optional)- if True, the coefficients are multiplied from the left
     1364                                      if False, the coefficients are multiplied from the right
     1365
     1366        Returns the linear combination lambda_1 v_1 + ... + lambda_k v_k resp.
     1367                the linear combination v_1 lambda_1 + ... + v_k lambda_k where
     1368                list_of_elements = [ v_1, ..., v_k ]
     1369                list_of_coefficients = [ lambda_1, ..., lambda_k ]
     1370
     1371        EXAMPLES::
     1372            sage: F = CombinatorialFreeModule(QQ,[1,2])
     1373            sage: f = F.an_element(); f
     1374            2*B[1] + 2*B[2]
     1375            sage: F.linear_combination( (f,i) for i in range(5) )
     1376            20*B[1] + 20*B[2]
     1377        """
     1378        return self._from_dict( dict_linear_combination( ( ( element._monomial_coefficients, coeff ) for element, coeff in iter_of_elements_coeff ), factor_on_left=factor_on_left ), remove_zeros=False )
    13431379
    13441380    def term(self, index, coeff=None):
    13451381        """
    class CombinatorialFreeModule(UniqueRepr 
    13621398        """
    13631399        if coeff is None:
    13641400            coeff = self.base_ring().one()
    1365         return self._from_dict({index: coeff})
     1401        return self._from_dict( {index: coeff} )
    13661402
    13671403    def _monomial(self, index):
    13681404        """
    class CombinatorialFreeModule(UniqueRepr 
    13721408            sage: F._monomial('a')
    13731409            B['a']
    13741410        """
    1375         return self.term(index, self.base_ring().one())
     1411        return self.term( index, self.base_ring().one() )
    13761412
    13771413    # This is generic, and should be lifted into modules_with_basis
    13781414    @lazy_attribute
    class CombinatorialFreeModule(UniqueRepr 
    14821518            sage: F.zero()
    14831519            0
    14841520        """
    1485         return self._from_dict({})
     1521        return self._from_dict({}, remove_zeros=False)
    14861522
    1487     def _from_dict(self, d, coerce=False):
     1523    def _from_dict( self, d, coerce=False, remove_zeros=True ):
    14881524        """
    14891525        Given a monomial coefficient dictionary ``d``, returns the
    14901526        element of self with those monomials
    class CombinatorialFreeModule(UniqueRepr 
    15091545            Rational Field
    15101546        """
    15111547        assert isinstance(d, dict)
     1548
     1549        R = self.base_ring()
     1550        zero = R( 0 )
     1551        for_removal = []
     1552
    15121553        if coerce:
    1513             R = self.base_ring()
    1514             # FIXME: this should remove zero entries
    1515             d = dict((m,R(c)) for m,c in d.iteritems())
    1516 
    1517         return self.element_class(self, d)
     1554            D = d.copy()
     1555            for key, coeff in D.iteritems():
     1556                if remove_zeros and coeff == zero:
     1557                    for_removal.append( key )
     1558                else:
     1559                    D[ key ] = R( coeff )
     1560            for key in for_removal:
     1561                del D[ key ]
     1562            return self.element_class( self, D )   
     1563        elif remove_zeros:
     1564            D = d.copy()
     1565            for key, coeff in D.iteritems():
     1566                if coeff == zero:
     1567                    for_removal.append( key )
     1568            for key in for_removal:
     1569                del D[ key ]
     1570            return self.element_class( self, D )
     1571        else:
     1572            return self.element_class( self, d )
    15181573
    15191574
    15201575class CombinatorialFreeModule_Tensor(CombinatorialFreeModule):
  • sage/combinat/sf/powersum.py

    diff --git a/sage/combinat/sf/powersum.py b/sage/combinat/sf/powersum.py
    a b class SymmetricFunctionAlgebra_power(mul 
    8989        """
    9090        p = self.parent()
    9191        if 1 not in part:
    92             return 0
     92            return p(0)
    9393        else:
    9494            return len([i for i in part if i == 1])*p(part[:-1])
    9595