Ticket #5093: trac5093-fast-callable-api.patch

File trac5093-fast-callable-api.patch, 9.7 KB (added by Carl Witty, 14 years ago)
  • sage/ext/fast_callable.pyx

    # HG changeset patch
    # User Carl Witty <cwitty@newtonlabs.com>
    # Date 1237434511 25200
    # Node ID d90665b8ed8a4f4653e177d9b2d1766dfb9cbf84
    # Parent  a97f9d176f07425f7dc6c9965a931152469b7bdf
    Remove features from the API that are likely to change, so I don't have to worry about deprecation later
    
    diff -r a97f9d176f07 -r d90665b8ed8a sage/ext/fast_callable.pyx
    a b  
    1616quickly.
    1717
    1818sage: f = sin(x) + 3*x^2
    19 sage: ff = fast_callable(f)
     19sage: ff = fast_callable(f, vars=[x])
    2020sage: ff(3.5)
    212136.3992167723104
    2222sage: ff(RIF(3.5))
     
    3333(x - 20)*(x - 19)*(x - 18)*(x - 17)*(x - 16)*(x - 15)*(x - 14)*(x - 13)*(x - 12)*(x - 11)*(x - 10)*(x - 9)*(x - 8)*(x - 7)*(x - 6)*(x - 5)*(x - 4)*(x - 3)*(x - 2)*(x - 1)
    3434sage: timeit('wilk.subs(x=30)') # random, long time
    3535625 loops, best of 3: 1.43 ms per loop
    36 sage: fc_wilk = fast_callable(wilk)
     36sage: fc_wilk = fast_callable(wilk, vars=[x])
    3737sage: timeit('fc_wilk(30)') # random, long time
    3838625 loops, best of 3: 9.72 us per loop
    3939
    4040You can specify a particular domain for the evaluation using
    4141\code{domain=}:
    4242
    43 sage: fc_wilk_zz = fast_callable(wilk, domain=ZZ)
     43sage: fc_wilk_zz = fast_callable(wilk, vars=[x], domain=ZZ)
    4444
    4545The meaning of domain=D is that each intermediate and final result
    4646is converted to type D.  For instance, the previous example of
     
    6868floating-point operations directly and skip all the Python object
    6969creations that you would get from actually using RDF objects.
    7070
    71 sage: fc_wilk_rdf = fast_callable(wilk, domain=RDF)
     71sage: fc_wilk_rdf = fast_callable(wilk, vars=[x], domain=RDF)
    7272sage: timeit('fc_wilk_rdf(30.0)') # random, long time
    7373625 loops, best of 3: 7 us per loop
    7474
     
    7878the return value is an RDF element, and when domain=float is used,
    7979the return value is a Python float.)
    8080
    81 sage: fc_wilk_float = fast_callable(wilk, domain=float)
     81sage: fc_wilk_float = fast_callable(wilk, vars=[x], domain=float)
    8282sage: timeit('fc_wilk_float(30.0)') # random, long time
    8383625 loops, best of 3: 5.04 us per loop
    8484
    8585We also have support for RR:
    8686
    87 sage: fc_wilk_rr = fast_callable(wilk, domain=RR)
     87sage: fc_wilk_rr = fast_callable(wilk, vars=[x], domain=RR)
    8888sage: timeit('fc_wilk_rr(30.0)') # random, long time
    8989625 loops, best of 3: 13 us per loop
    9090
    91 By default, \function{fast_callable} uses the same variable names in the
    92 same order that the \method{__call__} method on its argument would use;
    93 for instance, on symbolic expressions, the variables are used in alphabetical
    94 order.
     91Currently, \function{fast_callable} can accept two kinds of objects:
     92polynomials (univariate and multivariate) and symbolic expressions
     93(elements of the Symbolic Ring).  (This list is likely to grow
     94significantly in the near future.)  For polynomials, you can omit the
     95'vars' argument; the variables will default to the ring generators (in
     96the order used when creating the ring).
     97
     98sage: K.<x,y,z> = QQ[]
     99sage: p = 10*y + 100*z + x
     100sage: fp = fast_callable(p)
     101sage: fp(1,2,3)
     102321
     103
     104But you can also specify the variable names to override the default
     105ordering (you can include extra variable names here, too).
     106
     107sage: fp = fast_callable(p, vars=('x','w','z','y'))
     108
     109For symbolic expressions, you need to specify the variable names, so
     110that \function{fast_callable} knows what order to use.
    95111
    96112sage: var('y,z,x')
    97113(y, z, x)
    98114sage: f = 10*y + 100*z + x
    99 sage: f(1,2,3)
    100 321
    101 sage: ff = fast_callable(f)
     115sage: ff = fast_callable(f, vars=(x,y,z))
    102116sage: ff(1,2,3)
    103117321
    104118
    105 However, this can be overridden with \code{vars=}:
     119You can also specify extra variable names:
    106120
    107121sage: ff = fast_callable(f, vars=('x','w','z','y'))
    108122sage: ff(1,2,3,4)
     
    175189EXAMPLES:
    176190    sage: var('x')
    177191    x
    178     sage: f = fast_callable(sqrt(x^7+1), domain=float)
     192    sage: f = fast_callable(sqrt(x^7+1), vars=[x], domain=float)
    179193
    180194    sage: f(1)
    181195    1.4142135623730951
     
    280294
    281295include "stdsage.pxi"
    282296
    283 def fast_callable(x, domain=None, vars=None):
     297def fast_callable(x, domain=None, vars=None,
     298                  _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=False):
    284299    r"""
    285300    Given an expression x, compiles it into a form that can be quickly
    286301    evaluated, given values for the variables in x.
    287302
    288     x can be an expression object, or anything that has a .variables()
    289     method and a ._fast_callable_() method (this includes SR, univariate
    290     polynomials, and multivariate polynomials).
     303    Currently, x can be an expression object, an element of SR, or a
     304    (univariate or multivariate) polynomial; this list will probably
     305    be extended soon.
    291306
    292307    By default, x is evaluated the same way that a Python function
    293308    would evaluate it -- addition maps to PyNumber_Add, etc.  However,
     
    296311    have a special-purpose interpreter for that parent (like RDF or float),
    297312    domain=... will trigger the use of that interpreter.
    298313
    299     If vars is None, then we will attempt to determine the set of
    300     variables from x; otherwise, we will use the given set.
     314    If vars is None and x is a polynomial, then we will use the
     315    generators of parent(x) as the variables; otherwise, vars must be
     316    specified.
    301317
    302318    EXAMPLES:
    303319        sage: var('x')
    304320        x
    305321        sage: expr = sin(x) + 3*x^2
    306         sage: f = fast_callable(expr)
     322        sage: f = fast_callable(expr, vars=[x])
    307323        sage: f(2)
    308324        sin(2) + 12
    309325        sage: f(2.0)
     
    315331    the RDF interpreter; elements of RDF just don't display all
    316332    their digits.
    317333
    318         sage: f_float = fast_callable(expr, domain=float)
     334        sage: f_float = fast_callable(expr, vars=[x], domain=float)
    319335        sage: f_float(2)
    320336        12.909297426825681
    321         sage: f_rdf = fast_callable(expr, domain=RDF)
     337        sage: f_rdf = fast_callable(expr, vars=[x], domain=RDF)
    322338        sage: f_rdf(2)
    323339        12.9092974268
    324340        sage: f = fast_callable(expr, vars=('z','x','y'))
     
    361377        vars = et._etb._vars
    362378    else:
    363379        if vars is None or len(vars) == 0:
     380            from sage.calculus.calculus import SR
     381            if x.parent() is SR and not _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality:
     382                raise ValueError, "List of variables must be specified for symbolic expressions"
    364383            vars = x.variables()
    365384            # XXX This is pretty gross... there should be a "callable_variables"
    366385            # method that does all this.
    367             from sage.calculus.calculus import SR
    368386            from sage.rings.all import is_PolynomialRing, is_MPolynomialRing
    369387            if x.parent() is SR and x.number_of_arguments() > len(vars):
    370388                vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(len(vars), x.number_of_arguments())]
     
    15311549    TESTS:
    15321550        sage: def my_sin(x): return sin(x)
    15331551        sage: def my_norm(x, y): return x*x + y*y
    1534         sage: def my_sqrt(x): return sqrt(x, extend=False)
     1552        sage: def my_sqrt(x):
     1553        ...       if x < 0: raise ValueError, "sqrt of negative number"
     1554        ...       return sqrt(x, extend=False)
    15351555        sage: fc = fast_callable(expr, domain=RealField(130))
    15361556        sage: fc(0)
    15371557        3.1415926535897932384626433832795028842
     
    15701590        sage: fc(-3)
    15711591        Traceback (most recent call last):
    15721592        ...
    1573         ValueError: math domain error
     1593        ValueError: sqrt of negative number
    15741594        sage: fc = fast_callable(etb.call(my_sqrt, x), domain=RR)
    15751595        sage: fc(3)
    15761596        1.73205080756888
    15771597        sage: fc(-3)
    15781598        Traceback (most recent call last):
    15791599        ...
    1580         ValueError: negative number -3.00000000000000 does not have a square root in the real field
     1600        ValueError: sqrt of negative number
    15811601        sage: etb2 = ExpressionTreeBuilder(('y','z'))
    15821602        sage: y = etb2.var('y')
    15831603        sage: z = etb2.var('z')
     
    21572177        (Probably only useful when writing doctests.)
    21582178
    21592179        EXAMPLES:
    2160             sage: fast_callable(sin(x)/x, domain=RDF).get_orig_args()
     2180            sage: fast_callable(sin(x)/x, vars=[x], domain=RDF).get_orig_args()
    21612181            {'domain': Real Double Field, 'code': [0, 0, 16, 0, 0, 7, 2], 'py_constants': [], 'args': 1, 'stack': 2, 'constants': []}
    21622182        """
    21632183        return self._orig_args
     
    21672187        Return the list of instructions in this wrapper.
    21682188
    21692189        EXAMPLES:
    2170             sage: fast_callable(cos(x)*x, domain=RDF).op_list()
     2190            sage: fast_callable(cos(x)*x, vars=[x], domain=RDF).op_list()
    21712191            [('load_arg', 0), 'cos', ('load_arg', 0), 'mul', 'return']
    21722192        """
    21732193        return op_list(self._orig_args, self._metadata)
     
    21822202        this up by adding a new instruction to the interpreter.)
    21832203
    21842204        EXAMPLES:
    2185             sage: fast_callable(abs(sin(x)), domain=RDF).python_calls()
     2205            sage: fast_callable(abs(sin(x)), vars=[x], domain=RDF).python_calls()
    21862206            []
    2187             sage: fast_callable(abs(sin(factorial(x)))).python_calls()
     2207            sage: fast_callable(abs(sin(factorial(x))), vars=[x]).python_calls()
    21882208            [factorial, sin]
    21892209        """
    21902210        ops = self.op_list()
  • sage/ext/fast_eval.pyx

    diff -r a97f9d176f07 -r d90665b8ed8a sage/ext/fast_eval.pyx
    a b  
    13471347        if old:
    13481348            return f._fast_float_(*vars)
    13491349        else:
    1350             return fast_callable(f, vars=vars, domain=float)
     1350            return fast_callable(f, vars=vars, domain=float, _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=True)
    13511351    except AttributeError:
    13521352        pass
    13531353