Ticket #9651: trac_9651_CombinatorialFreeModule_Addition-cs.2.patch

File trac_9651_CombinatorialFreeModule_Addition-cs.2.patch, 25.9 KB (added by stumpc5, 11 years ago)
  • 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/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 remove_zeros( dict D ):
     12    """
     13    deletes all (key,0) in D
     14   
     15    EXAMPLES:
     16        sage: from sage.combinat.dict_addition import remove_zeros
     17        sage: D = { 0:1, 1:1, 2:0 }; D
     18        {0: 1, 1: 1, 2: 0}
     19        sage: remove_zeros( D ); D
     20        {0: 1, 1: 1}
     21    """
     22    for_removal = [ key for key, value in D.iteritems() if value == 0 ]
     23    for key in for_removal:
     24        del D[key]   
     25
     26def dict_addition( dict_iter ):
     27    """
     28    returns the pointwise addition of dictionaries with coefficients
     29   
     30    INPUT:
     31        dict_iter         -- iterator of dictionaries with values in a common ring R
     32       
     33    OUTPUT:
     34        dictionary containing all keys of dictionaries in dict_list (and non-zero values) being the the sum of the values in the different
     35        dictionaries
     36   
     37    EXAMPLES:
     38        sage: from sage.combinat.dict_addition import dict_addition
     39        sage: from sage.combinat.dict_addition import remove_zeros
     40        sage: D = { 0:1, 1:1 }; D
     41        {0: 1, 1: 1}
     42        sage: dict_addition( D for _ in range(5) )
     43        {0: 5, 1: 5}
     44    """
     45    cdef dict D, D_tmp
     46
     47    D = {}
     48    for D_tmp in dict_iter:
     49        if D == {}:
     50            D = D_tmp.copy()
     51        else:   
     52            for key, value in D_tmp.iteritems():
     53                if key in D:
     54                    D[ key ] += value
     55                else:
     56                    D[ key ]  = value
     57    remove_zeros( D )
     58    return D
     59
     60def dict_linear_combination( dict_factor_iter, factor_on_left=True ):
     61    """
     62    returns the pointwise addition of dictionaries with coefficients
     63   
     64    INPUT:
     65        dict_factor_iter            -- iterator of pairs D, coeff, where
     66                                        the D's are dictionaries with values in a common ring R
     67                                        the coeff's are coefficients in R
     68        factor_on_left(optional)    -- if True, the coefficients are multiplied on the left, otherwise they are multiplied on the right
     69       
     70    OUTPUT:
     71        dictionary containing all keys of dictionaries in dict_list (and non-zero values) being the the sum of the values in the different
     72        dictionaries each one first multiplied by the given factor
     73   
     74    EXAMPLES:
     75        sage: from sage.combinat.dict_addition import dict_linear_combination
     76        sage: from sage.combinat.dict_addition import remove_zeros
     77        sage: D = { 0:1, 1:1 }; D
     78        {0: 1, 1: 1}
     79        sage: dict_linear_combination( (D,i) for i in range(5) )
     80        {0: 10, 1: 10}
     81        sage: dict_linear_combination( [(D,1),(D,-1)] )
     82        {}
     83    """
     84    D = {}
     85    for D_tmp, fac_tmp in dict_factor_iter:
     86        if D == {} and fac_tmp == 1:
     87            D = D_tmp.copy()
     88        elif fac_tmp == 1:
     89            for key, value in D_tmp.iteritems():
     90                if key in D:
     91                    D[ key ] += value
     92                else:
     93                    D[ key ]  = value
     94        elif fac_tmp == -1:
     95            for key, value in D_tmp.iteritems():
     96                if key in D:
     97                    D[ key ]  -= value
     98                else:
     99                    D[ key ]   = -value
     100        else:
     101            if factor_on_left:
     102                for key, value in D_tmp.iteritems():
     103                    if key in D:
     104                        D[ key ] += fac_tmp * value
     105                    else:
     106                        D[ key ]  = fac_tmp * value
     107            else:
     108                for key, value in D_tmp.iteritems():
     109                    if key in D:
     110                        D[ key ] += value * fac_tmp
     111                    else:
     112                        D[ key ]  = value * fac_tmp
     113
     114    remove_zeros( D )
     115    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 ] ) )
    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 ) ] ) )
    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 ) ] ) )
    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 } ) 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 )
    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 )
    689672        else:
    690673            return self.map_coefficients(lambda c: _divide_if_possible(c, x))
    691674
    class CombinatorialFreeModule(UniqueRepr 
    811794        if R not in Rings():
    812795            raise TypeError, "Argument R must be a ring."
    813796        try:
    814             # R._one_element?
    815             z = R(Integer(1))
     797            z = R.one()
    816798        except:
    817799            raise ValueError, "R must have a unit element"
    818800
    class CombinatorialFreeModule(UniqueRepr 
    12621244        if c: return c
    12631245        return 0
    12641246
    1265     def _apply_module_morphism(self, x, f):
     1247    def _apply_module_morphism( self, x, on_basis, codomain=False ):
    12661248        """
    12671249        Returns the image of x under the module morphism defined by
    12681250        extending f by linearity.
    class CombinatorialFreeModule(UniqueRepr 
    12721254
    12731255        - ``x`` : a element of self
    12741256
    1275         - ``f``f - a function that takes in a combinatorial
     1257        - ``on_basis`` - a function that takes in a combinatorial
    12761258          object indexing a basis element and returns an element of the
    1277           target domain
     1259          codomain
     1260         
     1261        - ``codomain`` (optional) - the codomain of the morphism, otherwise it is computed using on_basis
    12781262
    12791263
    12801264        EXAMPLES::
    class CombinatorialFreeModule(UniqueRepr 
    12821266            sage: s = SFASchur(QQ)
    12831267            sage: a = s([3]) + s([2,1]) + s([1,1,1])
    12841268            sage: b = 2*a
    1285             sage: f = lambda part: len(part)
     1269            sage: f = lambda part: Integer( len(part) )
    12861270            sage: s._apply_module_morphism(a, f) #1+2+3
    12871271            6
    12881272            sage: s._apply_module_morphism(b, f) #2*(1+2+3)
    12891273            12
    12901274        """
    1291         res = 0
    1292         for m, c in x._monomial_coefficients.iteritems():
    1293             res += c*f(m)
    1294         return res
    12951275
     1276        if x == self.zero():
     1277            if not codomain:
     1278                B = self.basis()
     1279                keys = list( B.keys() )
     1280                if len( keys ) > 0:
     1281                    key = keys[0]
     1282                    codomain = on_basis( key ).parent()
     1283                else:
     1284                    raise ValueError, 'Codomain could not be determined'
    12961285
    1297     def _apply_module_endomorphism(self, a, f):
     1286            return codomain.zero()
     1287                   
     1288        else:
     1289            if not codomain:
     1290                keys = x.support()
     1291                key = keys[0]
     1292                codomain = on_basis( key ).parent()
     1293
     1294            if hasattr( codomain, 'linear_combination' ):
     1295                return codomain.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() )
     1296            else:
     1297                return_sum = codomain.zero()
     1298                for key, coeff in x._monomial_coefficients.iteritems():
     1299                    return_sum += coeff * on_basis( key )
     1300                return return_sum
     1301
     1302    def _apply_module_endomorphism(self, x, on_basis):
    12981303        """
    12991304        This takes in a function from the basis elements to the elements of
    13001305        self and applies it linearly to a. Note that
    class CombinatorialFreeModule(UniqueRepr 
    13081313            sage: s._apply_module_endomorphism( s([2,1]) + s([1,1,1]), f)
    13091314            2*s[2, 1] + 2*s[3]
    13101315        """
    1311         mcs = a.monomial_coefficients()
    1312         base_ring = self.base_ring()
    1313         zero = base_ring(0)
     1316        return self.linear_combination( ( on_basis( key ), coeff ) for key, coeff in x._monomial_coefficients.iteritems() )
    13141317
    1315         z_elt = {}
    1316         for basis_element in mcs:
    1317             f_mcs = f(basis_element).monomial_coefficients()
    1318             for f_basis_element in f_mcs:
    1319                 z_elt[ f_basis_element ] = z_elt.get(f_basis_element, zero) + mcs[basis_element]*f_mcs[f_basis_element]
     1318    def sum( self, iter_of_elements ):
     1319        """
     1320        overrides method inherited from commutative additive monoid as it is much faster on dicts directly
     1321       
     1322        INPUT:
     1323         - iter_of_elements: iterator of elements of self
    13201324
    1321         return self._from_dict(z_elt)
     1325        Returns the sum of all elements in iter_of_elements
     1326
     1327        EXAMPLES::
     1328            sage: F = CombinatorialFreeModule(QQ,[1,2])
     1329            sage: f = F.an_element(); f
     1330            2*B[1] + 2*B[2]
     1331            sage: F.sum( f for _ in range(5) )
     1332            10*B[1] + 10*B[2]
     1333        """
     1334   
     1335        D = dict_addition( element._monomial_coefficients for element in iter_of_elements )
     1336        return self._from_dict( D )
     1337
     1338    def linear_combination( self, iter_of_elements_coeff, factor_on_left=True ):
     1339        """
     1340        INPUT:
     1341         - iter_of_elements_coeff   -- iterator of pairs ( element, coeff ) with element in self and coeff in self.base_ring()
     1342         - factor_on_left (optional)- if True, the coefficients are multiplied from the left
     1343                                      if False, the coefficients are multiplied from the right
     1344
     1345        Returns the linear combination lambda_1 v_1 + ... + lambda_k v_k resp.
     1346                the linear combination v_1 lambda_1 + ... + v_k lambda_k where
     1347                list_of_elements = [ v_1, ..., v_k ]
     1348                list_of_coefficients = [ lambda_1, ..., lambda_k ]
     1349
     1350        EXAMPLES::
     1351            sage: F = CombinatorialFreeModule(QQ,[1,2])
     1352            sage: f = F.an_element(); f
     1353            2*B[1] + 2*B[2]
     1354            sage: F.linear_combination( (f,i) for i in range(5) )
     1355            20*B[1] + 20*B[2]
     1356        """
     1357        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 ) )
    13221358
    13231359    def term(self, index, coeff=None):
    13241360        """
    class CombinatorialFreeModule(UniqueRepr 
    13411377        """
    13421378        if coeff is None:
    13431379            coeff = self.base_ring().one()
    1344         return self._from_dict({index: coeff})
     1380        return self._from_dict( {index: coeff} )
    13451381
    13461382    def _monomial(self, index):
    13471383        """
    class CombinatorialFreeModule(UniqueRepr 
    13511387            sage: F._monomial('a')
    13521388            B['a']
    13531389        """
    1354         return self.term(index, self.base_ring().one())
     1390        return self.term( index, self.base_ring().one() )
    13551391
    13561392    # This is generic, and should be lifted into modules_with_basis
    13571393    @lazy_attribute
    class CombinatorialFreeModule(UniqueRepr 
    14631499        """
    14641500        return self._from_dict({})
    14651501
    1466     def _from_dict(self, d, coerce=False):
     1502    def _from_dict( self, d, coerce=False, remove_zeros=True ):
    14671503        """
    14681504        Given a monomial coefficient dictionary ``d``, returns the
    14691505        element of self with those monomials
    class CombinatorialFreeModule(UniqueRepr 
    14881524            Rational Field
    14891525        """
    14901526        assert isinstance(d, dict)
     1527
     1528        R = self.base_ring()
     1529        zero = R( 0 )
     1530        for_removal = []
     1531
    14911532        if coerce:
    1492             R = self.base_ring()
    1493             # FIXME: this should remove zero entries
    1494             d = dict((m,R(c)) for m,c in d.iteritems())
    1495 
    1496         return self.element_class(self, d)
     1533            D = d.copy()
     1534            for key, coeff in D.iteritems():
     1535                if remove_zeros and coeff == zero:
     1536                    for_removal.append( key )
     1537                else:
     1538                    D[ key ] = R( coeff )
     1539            for key in for_removal:
     1540                del D[ key ]
     1541            return self.element_class( self, D )   
     1542        elif remove_zeros:
     1543            D = d.copy()
     1544            for key, coeff in D.iteritems():
     1545                if coeff == zero:
     1546                    for_removal.append( key )
     1547            for key in for_removal:
     1548                del D[ key ]
     1549            return self.element_class( self, D )
     1550        else:
     1551            return self.element_class( self, d )
    14971552
    14981553
    14991554class 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