Hi!

Tickets #9944 and #9138 provide some nice features, but slow things
down. It seems to me that the reason of the performance loss is that
the patches from these tickets make the method resolution order of
polynomial rings much longer - in some cases the length doubles (15
versus 39 steps until <type 'object'> is reached).

As much as I understand: If the mro is longer than Python needs more
time to look up a method that is defined for a very basic class (such
as sage.structure.category_object.CategoryObject or
sage.structure.parent.Parent).

In the example, R is some polynomial ring, and the patches from the
tickets are applied, and the timings for R.base_ring() and
R.category() are better without the patches:

sage: R
Multivariate Polynomial Ring in x, y over Univariate Polynomial Ring
in t over Rational Field
sage: from sage.structure.category_object import CategoryObject
sage: timeit('R.base_ring()',number=10^6)
1000000 loops, best of 3: 453 ns per loop
sage: timeit('R.category()',number=10^6)
1000000 loops, best of 3: 1.13 µs per loop

There is a way to work around the method resolution order, and it
considerably speeds up the access of attributes:
sage: timeit('Parent.base_ring(R)',number=10^6)
1000000 loops, best of 3: 353 ns per loop
sage: timeit('CategoryObject.category(R)',number=10^6)
1000000 loops, best of 3: 331 ns per loop

My questions:

Shall we use the above idiom in basic arithmetic/coercion? These basic
methods are frequently used in arithmetic: R.__call__, for example,
contains 15 calls to .base_ring()!

Or is "Parent.base_ring(R)" not pythonic enough? Aparently, that idiom
is a nightmare for duck typing. On the other hand, in arithmetic, we
*now* that we have sub-classes of Parent and Element.

One way of improvement would be (at least in this concrete example) to
edit R.__call__, define base_ring=self.base_ring() once, and avoid the
other 14 method calls.

But I wonder: Does Python provide the possibility to declare
shortpaths for certain methods?

That's to say, when defining MPolynomialRing_polydict (say), can one
declare that the method "base_ring()" can be found in
sage.structure.category_object.CategoryObject, so that it is not
needed to walk down the mro?

Perhaps like this:
class Foo(Algebra):
    base_ring = CategoryObject.base_ring

Would that speed things up, and if "yes", is it considered good or bad
practice?

Python experts, please speak up!

Cheers,
Simon

-- 
To post to this group, send an email to sage-devel@googlegroups.com
To unsubscribe from this group, send an email to 
sage-devel+unsubscr...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org

Reply via email to