#10467: Improve lookup of private attributes
---------------------------+------------------------------------------------
   Reporter:  SimonKing    |       Owner:  tbd                     
       Type:  enhancement  |      Status:  new                     
   Priority:  major        |   Milestone:  sage-4.6.1              
  Component:  performance  |    Keywords:  private attribute lookup
     Author:  Simon King   |    Upstream:  N/A                     
   Reviewer:               |      Merged:                          
Work_issues:               |  
---------------------------+------------------------------------------------
 By a private attribute, I mean an attribute whose name starts with two
 underscores and does not end with an underscore. Such an attribute is
 used, e.g., in the default `__repr__` method of Sage objects.

 It should be reasonable to assume that private attributes belong to a
 particular instance, not to its class or its category. In particular, if
 `P` is a parent/element, then `P.__foo` is either defined for the instance
 `P` or will not be available from `P.category().parent_class` resp. from
 `P.category().element_class`.

 It turns out that this assumption holds thorought Sage: When one lets the
 `__getattr__` methods of Parent/Element immediately raise an
 `AttributeError` when a private attribute is requested, then all doc tests
 still pass.

 That is what my patch mainly does. In addition, it removes several
 occurences of an idiom like
 {{{
 if hasattr(self,'foo'):
     return self.foo
 }}}
 and replaces it with
 {{{
 try:
     return self.foo
 except AttributeError:
     pass
 }}}
 which saves half of the computation time when the attribute actually
 exists.

 The advantage is a considerable speedup. Here are two examples (the last
 is actually a serious computation):

 Without the patch:
 {{{
 sage: P.<x> = QQ[]
 sage: timeit('a=repr(x)')
 625 loops, best of 3: 74.7 µs per loop
 sage: R.<x,y> = InfinitePolynomialRing(QQ)
 sage: I = R.ideal([x[1]^2+y[2]*y[3], x[2]*y[1]*x[3]-y[1]*y[2]])
 sage: %time I.groebner_basis()
 CPU times: user 23.09 s, sys: 0.02 s, total: 23.11 s
 Wall time: 23.67 s
 [y_2*y_1^3 + y_2*y_1^2, y_2^2*y_1 - y_2*y_1^2, y_3*y_1 - y_2*y_1,
 x_1*y_2*y_1^2 + x_1*y_2*y_1, x_1^2 + y_2*y_1, x_2*y_2*y_1 - x_1*y_2*y_1,
 x_2*x_1*y_3 - y_2*y_1, x_3*y_2*y_1 - x_1*y_2*y_1, x_3*x_1*y_2 - y_2*y_1,
 x_3*x_2*y_1 - y_2*y_1]
 }}}

 With the patch:
 {{{
 sage: P.<x> = QQ[]
 sage: timeit('a=repr(x)')
 625 loops, best of 3: 40.5 µs per loop
 sage: R.<x,y> = InfinitePolynomialRing(QQ)
 sage: I = R.ideal([x[1]^2+y[2]*y[3], x[2]*y[1]*x[3]-y[1]*y[2]])
 sage: %time I.groebner_basis()
 CPU times: user 14.43 s, sys: 0.03 s, total: 14.46 s
 Wall time: 14.53 s
 [y_2*y_1^3 + y_2*y_1^2, y_2^2*y_1 - y_2*y_1^2, y_3*y_1 - y_2*y_1,
 x_1*y_2*y_1^2 + x_1*y_2*y_1, x_1^2 + y_2*y_1, x_2*y_2*y_1 - x_1*y_2*y_1,
 x_2*x_1*y_3 - y_2*y_1, x_3*y_2*y_1 - x_1*y_2*y_1, x_3*x_1*y_2 - y_2*y_1,
 x_3*x_2*y_1 - y_2*y_1]
 }}}

 The patch also adds doctests in `Parent.__getattr__`,
 `Element.__getattr__` and several methods of `SageObject`.

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/10467>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sage-trac?hl=en.

Reply via email to