1 | initial version |
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
.