This is a really excellent response!
Do you think it should be added to the FAQ on the wiki ("I wanted to find
the code for a function using
sage: foo??
but couldn't. What is going on here?"),
or is it too technical?
On Wed, Oct 6, 2010 at 6:55 AM, Jason Grout <[email protected]> wrote:
> 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
>
--
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