On 10/6/10 2:15 AM, Jeroen Demeyer wrote:
On 2010-10-06 02:04, François Bissey wrote:
I would like to see the source code of
sage.matrix.matrix_modn_sparse.Matrix_modn_sparse.__eq__(), but I have
no idea where to look.
sage/matrix/matrix_modn_sparse.pyx ?
Well, I obviously looked there, but didn't find it.
More precisely, I am looking for the location of the code which compares
a Matrix_modn_sparse with a Matrix_modn_dense. I.e. I want to see the
code for
sage: L = matrix(GF(43), 3, 3, range(9), sparse=True)
sage: R = matrix(GF(43), 3, 3, range(9))
sage: type(L)
<type 'sage.matrix.matrix_modn_sparse.Matrix_modn_sparse'>
sage: type(R)
<type 'sage.matrix.matrix_modn_dense.Matrix_modn_dense'>
sage: L==R # Where is this implemented?
True
You can use the coercion model code to understand more about what
happens [1]:
sage: cm = sage.structure.element.get_coercion_model(); cm
<sage.structure.coerce.CoercionModel_cache_maps object at 0x101fb4770>
sage: sage: L = matrix(GF(43), 3, 3, range(9), sparse=True)
sage: sage: R = matrix(GF(43), 3, 3, range(9))
sage: cm.explain(L,R,operator.eq)
Equal but distinct parents.
Coercion on right operand via
Call morphism:
From: Full MatrixSpace of 3 by 3 dense matrices over Finite Field
of size 43
To: Full MatrixSpace of 3 by 3 sparse matrices over Finite
Field of size 43
Arithmetic performed after coercions.
Result lives in Full MatrixSpace of 3 by 3 sparse matrices over Finite
Field of size 43
Full MatrixSpace of 3 by 3 sparse matrices over Finite Field of size 43
This says that both are converted to sparse matrices before the
comparison happens. Looking at the code, we see that there is a
__richcmp__ (the cython equivalent of __cmp__ [2]) in the
matrix_modn_sparse.pyx file:
def __richcmp__(matrix.Matrix self, right, int op): # always need
for mysterious reasons.
return self._richcmp(right, op)
This is not defined in the matrix/ directory:
~/sage/devel/sage/sage/matrix% grep "def _richcmp[^_]" *.py*
~/sage/devel/sage/sage/matrix%
So we go up the chain and look in structure/ directory, and find it is
defined in devel/sage/sage/structure/element.pyx in the Element class,
which ends with:
return left._richcmp_c_impl(right, op)
and we also see a comment following the function:
####################################################################
# For a derived Cython class, you **must** put the following in
# your subclasses, in order for it to take advantage of the
# above generic comparison code. You must also define
# either _cmp_c_impl (if your subclass is totally ordered),
# _richcmp_c_impl (if your subclass is partially ordered), or both
# (if your class has both a total order and a partial order;
# then the total order will be available with cmp(), and the partial
# order will be available with the relation operators; in this case
# you must also define __cmp__ in your subclass).
# This is simply how Python works.
The _richcmp_c_impl is not defined in the matrix/ directory, so it must
also be inherited. Indeed, the _richcmp_c_impl method just below the
comment above is:
cdef _richcmp_c_impl(left, Element right, int op):
if (<Element>left)._richcmp_c_impl == Element._richcmp_c_impl and \
(<Element>left)._cmp_c_impl == Element._cmp_c_impl:
# Not implemented, try some basic defaults
if op == Py_EQ:
return left is right
elif op == Py_NE:
return left is not right
return left._rich_to_bool(op, left._cmp_c_impl(right))
so the _cmp_c_impl is called. So we need to go back down and see where
_cmp_c_impl. That's back in matrix/matrix_sparse.pyx:
cdef int _cmp_c_impl(self, Element right) except -2:
return cmp(self._dict(), right._dict())
So in the end, the dictionaries are compared, after the dense matrix is
coerced to a sparse matrix.
As for the "mysteriously needed" reason? Cython calls __richcmp__,
which needs to call the coercion framework _richcmp function. I guess
the mysterious part is that __richcmp__ is not inherited. Well,
according to the Python/C API docs [3], either all of __hash__, __cmp__,
and __richcmp__ are inherited, or none are. So I guess we need the
__richcmp__ function copied into the matrix/*.pyx files because __hash__
is redefined, so __richcmp__ isn't inherited.
At least, that's how I see it.
Thanks,
Jason
[1] http://www.sagemath.org/doc/reference/coercion.html, specifically
http://www.sagemath.org/doc/reference/coercion.html#basic-arithmetic-rules
[2]
http://docs.cython.org/src/userguide/special_methods.html#rich-comparisons
[3] see the thread
http://www.mail-archive.com/[email protected]/msg07374.html or
the docs
http://docs.python.org/c-api/typeobj.html?highlight=__hash__#tp_richcompare
--
To post to this group, send an email to [email protected]
To unsubscribe from this group, send an email to
[email protected]
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org