#10467: Improve lookup of private attributes
---------------------------+------------------------------------------------
   Reporter:  SimonKing    |       Owner:  tbd                     
       Type:  enhancement  |      Status:  needs_review            
   Priority:  major        |   Milestone:  sage-4.6.1              
  Component:  performance  |    Keywords:  private attribute lookup
     Author:  Simon King   |    Upstream:  N/A                     
   Reviewer:               |      Merged:                          
Work_issues:               |  
---------------------------+------------------------------------------------
Changes (by SimonKing):

  * status:  new => needs_review


Old description:

> 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`.

New description:

 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; after all, they are
 subject to Python's name mangling.

 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#comment:1>
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