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

Reply via email to