Changes between Initial Version and Version 10 of Ticket #9556


Ignore:
Timestamp:
06/19/13 18:05:52 (6 years ago)
Author:
burcin
Comment:

I uploaded a new patch that uses Mike's dynamic class idea, but applies to all code paths that might generate symbolic expressions with minimal speed penalty. Please review.

Patchbot, apply only trac_9556-dynamic_class_everywhere.patch.

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #9556

    • Property Status changed from new to needs_review
    • Property Work issues changed from to segfaulting doctests
    • Property Authors changed from to Burcin Erocal, Simon King, Mike Hansen
    • Property Cc burcin kcrisman vbraun added
    • Property Owner changed from segfaulting doctests to (none)
  • Ticket #9556 – Description

    initial v10  
    1 Let {{{e}}} be a symbolic expression. It may happen that {{{e.operator()}}} has a certain callable attribute, say, {{{foo}}}, that is not a method of {{{Function}}}. In this situation, one would like to use {{{e.foo()}}}, which is supposed to return {{{e.operator().foo(*e.operands())}}} - apparently this is useful for working with hypergeometric functions.
     1Let {{{e}}} be a symbolic expression. It may happen that {{{e.operator()}}} has a certain callable attribute, say, {{{foo}}}, that is not a method of {{{Function}}}. In this situation, one would like to use {{{e.foo()}}}, which is supposed to return {{{e.operator().foo(*e.operands())}}} - apparently this is useful for working with hypergeometric functions (#2516).
    22
    33'''__Example__'''
    44
    55{{{
    6 sage: from sage.symbolic.function import BuiltinFunction
    7 sage: class ExampleBuiltin(BuiltinFunction):
    8 ...     def __init__(self):
    9 ...         BuiltinFunction.__init__(self, 'ex_func', nargs=0) #arbitrary no of args
    10 ...     def some_function_name(self, *args):
    11 ...         return len(args)
    12 ...
    13 sage: ex_func = ExampleBuiltin()
    14 sage: ex_func
    15 ex_func
     6       sage: from sage.symbolic.function import BuiltinFunction
     7        sage: class TFunc(BuiltinFunction):
     8        ....:     def __init__(self):
     9        ....:         BuiltinFunction.__init__(self, 'tfunc', nargs=1)
     10        ....:
     11        ....:     class EvaluationMethods:
     12        ....:         def argp1(self, x):
     13        ....:             '''
     14        ....:             Some documentation about a bogus function.
     15        ....:             '''
     16        ....:             return x+1
     17        ....:
     18        ....:         @property
     19        ....:         def foo(self):
     20        ....:             return 5
     21        ....:
     22        sage: tfunc = TFunc()
     23        sage: e = tfunc(x); e
     24        tfunc(x)
     25        sage: type(e)
     26        <class '__main__.Expression_with_dynamic_methods'>
     27        sage: e.argp1()
     28        x + 1
     29        sage: e.foo
     30        5
     31        sage: x.argp1()
     32        Traceback (most recent call last):
     33        ...
     34        AttributeError: 'sage.symbolic.expression.Expression' object has no
     35        attribute 'argp1'
     36        sage: t = (e + 1).op[0]; t
     37        tfunc(x)
     38        sage: t
     39        tfunc(x)
     40        sage: type(t)
     41        <class '__main__.Expression_with_dynamic_methods'>
     42        sage: t.argp1()
     43        x + 1
     44        sage: import sagenb.misc.support as s
     45        sage: s.completions('t.argp', globals(), system='python')
     46        ['t.argp1']
     47        sage: t.argp1.__doc__.strip()
     48        'Some documentation about a bogus function.'
    1649}}}
    1750
    18 We obtain a symbolic expression by calling {{{ex_func}}}:
    19 {{{
    20 sage: e = ex_func(x,x+1, x+2)
    21 sage: type(e)
    22 <type 'sage.symbolic.expression.Expression'>
    23 }}}
    24 
    25 We add a callable and a non-callable attribute to {{{ex_func}}}:
    26 {{{
    27 sage: def some_function(slf, *L): print slf,'called with',L
    28 ...
    29 sage: ex_func.foo_bar = some_function
    30 sage: ex_func.bar_foo = 4
    31 }}}
    32 
    33 Now, both the new method and the callable attribute {{{foo_bar}}} of
    34 {{{ex_func}}} are available from {{{e}}}, but not the non-callable:
    35 
    36 {{{
    37 sage: e.some_function_name()
    38 3
    39 sage: e.foo_bar()
    40 ex_func called with (x, x + 1, x + 2)
    41 sage: e.bar_foo
    42 Traceback (most recent call last):
    43 ...
    44 AttributeError: <type 'sage.symbolic.expression.Expression'> has no attribute 'bar_foo'
    45 }}}
    46 
    47 Tab completion  and introspection work:
    48 
    49 {{{
    50 sage: 'foo_bar' in dir(e)     # indirect doctest
    51 True
    52 sage: 'some_function_name' in dir(e)
    53 True
    54 sage: 'bar_foo' in dir(e)
    55 False
    56 sage: import sagenb.misc.support as s
    57 sage: s.completions('e.some', globals(), system='python')
    58 ['e.some_function_name']
    59 }}}
    60 
    61 '''__Problems__'''
    62 
    63 When I ran {{{sage -testall}}}, several doctests segfaulted:
    64 {{{
    65         sage -t  -verbose "devel/sage/sage/functions/hyperbolic.py"
    66         sage -t  -verbose "devel/sage/sage/games/hexad.py"
    67         sage -t  -verbose "devel/sage/sage/matrix/tests.py"
    68         sage -t  -verbose "devel/sage/sage/misc/sage_eval.py"
    69         sage -t  -verbose "devel/sage/sage/plot/animate.py"
    70         sage -t  -verbose "devel/sage/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py"
    71         sage -t  -verbose "devel/sage/sage/rings/polynomial/polynomial_element.pyx"
    72 }}}
    73 
    74 I tried (using {{{sage -t -verbose}}}) to find out what exactly fails. When I ran some of these failing examples in an interactive session, no segfault occured. So, is there a nasty side effect?
     51Apply: [[attachment:trac_9556-dynamic_class_everywhere.patch]]