# Coercion not commutative

I implemented a new algebraic structure A, derived from CommutativeAlgebra (over the rationals QQ) with element class Aelement derived from CommutativeAlgebraElement. The method A._element_constructor_ can, in particular, coerce an element from QQ into an element Aelement and this works fine if done explicitly. Also if I multiply an element from A with an element from QQ from the right-hand side everything works and the rational number is properly coerced to A. However, if I multiply an element from QQ with an element from A I get an error and the coercion does not work:

sage: A(QQ(2)) # works
sage: C.has_coerce_map_from(QQ)
True
sage: A.an_element()*QQ(2) # works
sage: ZZ(2)*A.an_element() # works
sage: QQ(2)*A.an_element() # does not work


The last call yields the error:

~/sage-9.2/local/lib/python3.8/site-packages/sage/rings/rational.pyx in sage.rings.rational.Rational.__mul__ (build/cythonized/sage/rings/rational.c:20912)()
2399             return x
2400
-> 2401         return coercion_model.bin_op(left, right, operator.mul)
2402
2403     cpdef _mul_(self, right):

~/sage-9.2/local/lib/python3.8/site-packages/sage/structure/coerce.pyx in sage.structure.coerce.CoercionModel.bin_op (build/cythonized/sage/structure/coerce.c:11304)()
1246         # We should really include the underlying error.
1247         # This causes so much headache.
-> 1248         raise bin_op_exception(op, x, y)
1249
1250     cpdef canonical_coercion(self, x, y):

TypeError: unsupported operand parent(s) for *: 'Rational Field' and 'A'


Does someone know what the problem could be? If no one has an idea, I will try to provide a minimal example which exhibits the error. Thank you!

edit retag close merge delete

Could you please provide the whole code so that we can reproduce ?

( 2021-09-01 15:53:51 +0100 )edit

I will try to provide a minimal example which shows the error tomorrow.

( 2021-09-01 16:23:34 +0100 )edit

Sort by » oldest newest most voted

The mistake was quite stupid: The structure A is defined over some base ring. For checking equality of the algebraic structures I used:

def __eq__(self, right):
try:
return self.base_ring() == right.base_ring()
except:
return False


However, since QQ.base_ring() is QQ, this meant that A over QQ and QQ itself were considered equal. Hence, sage thought there is also a coercion from A to QQ (and not only from QQ to A). Therefore, for QQ(2)*A.an_element() sage tried to convert A.an_element() to a rational which failed. On the other hand, A.an_element()*QQ(2) worked because QQ(2) could indeed be converted to an element of A. My fix was to simply change the equality function to something like

def __eq__(self, right):
if not isinstance(right, A) :
return False
try:
return self.base_ring() == right.base_ring()
except:
return False

more