Revision history [back]

As far as I understand it, when you call CombinatorialFreeModule(R, basis_keys), it doesn't call its __init__ method right away: first it calls its __classcall_private__ method, which does things like convert basis_keys to a hashable type:

    if isinstance(basis_keys, (list, tuple)):
basis_keys = FiniteEnumeratedSet(basis_keys)


Then this gets passed to the __init__ method. As a result, giving the same names for the generators results in the identical object (not just equal, but identical):

sage: M1 = CombinatorialFreeModule(ZZ, ['a', 'b', 'c'])
sage: M2 = CombinatorialFreeModule(ZZ, ('a', 'b', 'c'))
sage: M1 is M2
True


This works for me:

from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement

class TestRingElement(CombinatorialFreeModuleElement):

def __init__(self, M, x):
super(TestRingElement, self).__init__(M, x)
self.data = x

class TestRing(CombinatorialFreeModule):

Element = TestRingElement

@staticmethod
def __classcall__(self, R, G):
from sage.sets.all import FiniteEnumeratedSet
if isinstance(G, (list, tuple)):
G = FiniteEnumeratedSet(G)
return super(TestRing, self).__classcall__(self, R, G)

def __init__(self, R, G):
CombinatorialFreeModule.__init__(self, R, G)


You could check the Sage library for other classes which are based on CombinatorialFreeModule. I wrote the code in sage.algebras.steenrod.steenrod_algebra, for instance. A simpler example is in sage.categories.examples.hopf_algebras_with_basis.