Ticket #5572: improve_fast_callable.2.patch

File improve_fast_callable.2.patch, 77.1 KB (added by jason, 10 years ago)

rebase to 4.4.1

  • module_list.py

    # HG changeset patch
    # User Jason Grout <jason-sage@creativetrax.com>
    # Date 1272108645 18000
    # Node ID 33d569c5906f5054bdefa11a72bf0de15d0005aa
    # Parent  338637719747111e3f30c1f1c3a1dee84d0e9d12
    [mq]: improve_fast_callable.patch
    
    diff -r 338637719747 -r 33d569c5906f module_list.py
    a b  
    212212    Extension('sage.ext.fast_callable',
    213213              sources = ['sage/ext/fast_callable.pyx']),
    214214   
    215     Extension('sage.ext.fast_eval',
    216               sources = ['sage/ext/fast_eval.pyx']),
     215#    Extension('sage.ext.fast_eval',
     216#              sources = ['sage/ext/fast_eval.pyx']),
    217217   
    218218    Extension('sage.ext.interactive_constructors_c',
    219219              sources = ['sage/ext/interactive_constructors_c.pyx']),
  • sage/all.py

    diff -r 338637719747 -r 33d569c5906f sage/all.py
    a b  
    136136from sage.parallel.all   import *
    137137
    138138from sage.ext.fast_callable  import fast_callable
    139 from sage.ext.fast_eval      import fast_float
    140139
    141140from copy import copy, deepcopy
    142141
  • sage/ext/fast_callable.pyx

    diff -r 338637719747 -r 33d569c5906f sage/ext/fast_callable.pyx
    a b  
    385385        0.55142668124169059
    386386    """
    387387    cdef Expression et
    388     if isinstance(x, Expression):
     388
     389    if isinstance(x, (tuple, list)):
     390        return tuple([fast_callable(xi, domain=domain, vars=vars,
     391                                    _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=_autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality,
     392                                    expect_one_var=expect_one_var) for xi in x])
     393
     394    import inspect
     395    if isinstance(x,Wrapper):
     396        return x # TODO: make it so that we can change the domain/variables.
     397    elif inspect.isfunction(x):
     398        args=inspect.getargspec(x)
     399        if args.defaults is None:
     400            vars=args.args
     401        else:
     402            vars=args.args[:-len(args.defaults)]
     403        etb = ExpressionTreeBuilder(vars=vars, domain=domain)
     404        et = etb.call(x,*map(etb.var, vars))
     405    elif isinstance(x, Expression):
    389406        et = x
    390407        vars = et._etb._vars
    391408    else:
    392         if vars is None or len(vars) == 0:
    393             from sage.symbolic.ring import SR
    394             from sage.symbolic.callable import is_CallableSymbolicExpressionRing
    395             from sage.symbolic.expression import is_Expression
    396 
    397             # XXX This is pretty gross... there should be a "callable_variables"
    398             # method that does all this.
    399             vars = x.variables()
    400             if x.parent() is SR and x.number_of_arguments() > len(vars):
    401                 vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(len(vars), x.number_of_arguments())]
    402 
    403             # Failing to specify the variables is deprecated for any
    404             # symbolic expression, except for PrimitiveFunction and
    405             # CallableSymbolicExpression.           
    406             if is_Expression(x) and not is_CallableSymbolicExpressionRing(x.parent()):
    407                 if expect_one_var and len(vars) <= 1:
    408                     if len(vars) == 0:
    409                         vars = ['EXTRA_VAR0']
    410                 else:
    411                     if _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality:
    412                         from sage.misc.misc import deprecation
    413                         deprecation("Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)")
    414                     else:
    415                         raise ValueError, "List of variables must be specified for symbolic expressions"
    416             from sage.rings.all import is_PolynomialRing, is_MPolynomialRing
    417             if is_PolynomialRing(x.parent()) or is_MPolynomialRing(x.parent()):
    418                 vars = x.parent().variable_names()
     409        vars = callable_variables(x, vars=vars, expect_one_var=expect_one_var, _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=_autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality)
    419410        etb = ExpressionTreeBuilder(vars=vars, domain=domain)
    420411        et = x._fast_callable_(etb)
     412
     413    builder, str = choose_domain(domain, len(vars))
     414    generate_code(et, str)
     415    str.instr('return')
     416    return builder(str.get_current())
     417
     418def choose_domain(domain, nvars):
     419    r"""
     420    TODO: Docs
     421    """
    421422    if isinstance(domain, RealField_class):
    422423        import sage.ext.interpreters.wrapper_rr
    423424        builder = sage.ext.interpreters.wrapper_rr.Wrapper_rr
    424 
    425425        str = InstructionStream(sage.ext.interpreters.wrapper_rr.metadata,
    426426                                len(vars),
    427427                                domain)
     
    429429        import sage.ext.interpreters.wrapper_rdf
    430430        builder = sage.ext.interpreters.wrapper_rdf.Wrapper_rdf
    431431        str = InstructionStream(sage.ext.interpreters.wrapper_rdf.metadata,
    432                                 len(vars),
     432                                nvars,
    433433                                domain)
    434434    elif domain == CDF:
    435435        import sage.ext.interpreters.wrapper_cdf
    436436        builder = sage.ext.interpreters.wrapper_cdf.Wrapper_cdf
    437437        str = InstructionStream(sage.ext.interpreters.wrapper_cdf.metadata,
    438                                 len(vars),
     438                                nvars,
    439439                                domain)
    440440    elif domain is None:
    441441        import sage.ext.interpreters.wrapper_py
    442442        builder = sage.ext.interpreters.wrapper_py.Wrapper_py
    443443        str = InstructionStream(sage.ext.interpreters.wrapper_py.metadata,
    444                                 len(vars))
     444                                nvars)
    445445    else:
    446446        import sage.ext.interpreters.wrapper_el
    447447        builder = sage.ext.interpreters.wrapper_el.Wrapper_el
    448448        str = InstructionStream(sage.ext.interpreters.wrapper_el.metadata,
    449                                 len(vars),
     449                                nvars,
    450450                                domain)
    451     generate_code(et, str)
    452     str.instr('return')
    453     return builder(str.get_current())
     451    return builder, str
    454452
    455453def function_name(fn):
    456454    r"""
     
    484482    except AttributeError:
    485483        return "{%r}" % fn
    486484
     485def fast_callable_arg(int n, nargs, domain):
     486    r"""
     487    Return a fast_callable function that merely returns a
     488    specific variable number out of nvars variables.
     489    """
     490    cdef Expression et
     491    etb = ExpressionTreeBuilder(vars=['v%d'%i for i in range(nargs)], domain=domain)
     492    et = etb.var('v%d'%n)
     493    builder, str = choose_domain(domain, nargs)
     494    generate_code(et, str)
     495    str.instr('return')
     496    return builder(str.get_current())
     497
     498
     499   
    487500cdef class ExpressionTreeBuilder:
    488501    r"""
    489502    A class with helper methods for building Expressions.
     
    15511564    builtin_functions[func_all.abs_symbolic] = 'abs'
    15521565    return builtin_functions
    15531566
     1567
     1568
     1569
     1570def callable_variables(x, vars, expect_one_var, _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality):
     1571    r"""
     1572    Determines a list of callable variables from the expression
     1573    """
     1574    from sage.symbolic.callable import is_CallableSymbolicExpression
     1575   
     1576    if is_CallableSymbolicExpression(x):
     1577        vars=x.args()
     1578    elif vars is None or len(vars) == 0:
     1579        from sage.symbolic.ring import SR
     1580        from sage.symbolic.callable import is_CallableSymbolicExpressionRing
     1581        from sage.symbolic.expression import is_Expression
     1582
     1583        try:
     1584            vars = x.variables()
     1585        except AttributeError:
     1586            vars = []
     1587        if x.parent() is SR and x.number_of_arguments() > len(vars):
     1588            vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(len(vars), x.number_of_arguments())]
     1589
     1590        # Failing to specify the variables is deprecated for any
     1591        # symbolic expression, except for PrimitiveFunction and
     1592        # CallableSymbolicExpression.           
     1593        if is_Expression(x) and not is_CallableSymbolicExpressionRing(x.parent()):
     1594            if expect_one_var and len(vars) <= 1:
     1595                if len(vars) == 0:
     1596                    vars = ['EXTRA_VAR0']
     1597            else:
     1598                if _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality:
     1599                    from sage.misc.misc import deprecation
     1600                    deprecation("Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)")
     1601                else:
     1602                    raise ValueError, "List of variables must be specified for symbolic expressions"
     1603        from sage.rings.all import is_PolynomialRing, is_MPolynomialRing
     1604        if is_PolynomialRing(x.parent()) or is_MPolynomialRing(x.parent()):
     1605            vars = x.parent().variable_names()
     1606    return vars
     1607
    15541608cpdef generate_code(Expression expr, stream):
    15551609    r"""
    15561610    Generate code from an Expression tree; write the result into an
  • deleted file sage/ext/fast_eval.pxd

    diff -r 338637719747 -r 33d569c5906f sage/ext/fast_eval.pxd
    + -  
    1 cdef union double_op_params:
    2     void* func
    3     double c
    4     int n
    5 
    6 cdef struct fast_double_op:
    7     char type
    8     double_op_params params   
    9 
    10 cdef class FastDoubleFunc:
    11     cdef readonly int max_height
    12     cdef readonly int nargs
    13     cdef readonly int nops
    14     cdef fast_double_op* ops
    15    
    16     cdef double* argv
    17     cdef double* stack
    18        
    19     # need to keep this around because structs can't contain (ref-counted) python objects
    20     cdef py_funcs
    21    
    22     cdef int allocate_stack(FastDoubleFunc self) except -1
    23     cdef double _call_c(FastDoubleFunc self, double* argv) except? -2
    24     cpdef bint is_pure_c(self)
    25     cdef FastDoubleFunc cfunc(FastDoubleFunc self, void* func)
    26     cdef FastDoubleFunc unop(FastDoubleFunc self, char type)
  • deleted file sage/ext/fast_eval.pyx

    diff -r 338637719747 -r 33d569c5906f sage/ext/fast_eval.pyx
    + -  
    1 r"""
    2 Fast Numerical Evaluation.
    3 
    4 For many applications such as numerical integration, differential
    5 equation approximation, plotting a 3d surface, optimization problems,
    6 monte-carlo simulations, etc., one wishes to pass around and evaluate
    7 a single algebraic expression many, many times at various floating
    8 point values. Doing this via recursive calls over a python
    9 representation of the object (even if Maxima or other outside packages
    10 are not involved) is extremely inefficient.
    11 
    12 Up until now the solution has been to use lambda expressions, but this
    13 is neither intuitive, Sage-like, nor efficient (compared to operating
    14 on raw C doubles).  This module provides a representation of algebraic
    15 expression in Reverse Polish Notation, and provides an efficient
    16 interpreter on C double values as a callable python object. It does
    17 what it can in C, and will call out to Python if necessary.
    18 
    19 Essential to the understanding of this class is the distinction
    20 between symbolic expressions and callable symbolic expressions (where
    21 the latter binds argument names to argument positions). The
    22 \code{*vars} parameter passed around encapsulates this information.
    23 
    24 See the function \code{fast_float(f, *vars)} to create a fast-callable
    25 version of f.
    26 
    27 NOTE: Sage temporarily has two implementations of this functionality;
    28 one in this file, which will probably be deprecated soon, and one in
    29 fast_callable.pyx.  The following instructions are for the old
    30 implementation; you probably want to be looking at fast_callable.pyx
    31 instead.
    32 
    33 To provide this interface for a class, implement
    34 \code{_fast_float_(self, *vars)}.  The basic building blocks are
    35 provided by the functions \code{fast_float_constant} (returns a
    36 constant function), \code{fast_float_arg} (selects the $n$-th value
    37 when called with $\ge n$ arguments), and \code{fast_float_func} which
    38 wraps a callable Python function. These may be combined with the
    39 standard Python arithmetic operators, and support many of the basic
    40 math functions such sqrt, exp, and trig functions.
    41 
    42 EXAMPLES:
    43     sage: from sage.ext.fast_eval import fast_float
    44     sage: f = fast_float(sqrt(x^7+1), 'x', old=True)
    45     sage: f(1)
    46     1.4142135623730951
    47     sage: f.op_list()
    48     ['load 0', 'push 7.0', 'pow', 'push 1.0', 'add', 'call sqrt(1)']
    49    
    50     To interpret that last line, we load argument 0 ('x' in this case) onto
    51     the stack, push the constant 2.0 onto the stack, call the pow function
    52     (which takes 2 arguments from the stack), push the constant 1.0, add the
    53     top two arguments of the stack, and then call sqrt.
    54 
    55 Here we take sin of the first argument and add it to f:
    56     sage: from sage.ext.fast_eval import fast_float_arg
    57     sage: g = fast_float_arg(0).sin()
    58     sage: (f+g).op_list()
    59     ['load 0', 'push 7.0', 'pow', 'push 1.0', 'add', 'call sqrt(1)', 'load 0', 'call sin(1)', 'add']
    60 
    61 TESTS:
    62 This used to segfault because of an assumption that assigning None to a
    63 variable would raise a TypeError:
    64     sage: from sage.ext.fast_eval import fast_float_arg, fast_float
    65     sage: fast_float_arg(0)+None
    66     Traceback (most recent call last):
    67     ...
    68     TypeError
    69 
    70 AUTHOR:
    71     -- Robert Bradshaw (2008-10): Initial version
    72 """
    73 
    74 
    75 #*****************************************************************************
    76 #       Copyright (C) 2008 Robert Bradshaw <robertwb@math.washington.edu>
    77 #
    78 #  Distributed under the terms of the GNU General Public License (GPL)
    79 #
    80 #    This code is distributed in the hope that it will be useful,
    81 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
    82 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    83 #    General Public License for more details.
    84 #
    85 #  The full text of the GPL is available at:
    86 #
    87 #                  http://www.gnu.org/licenses/
    88 #*****************************************************************************
    89 
    90 from sage.ext.fast_callable import fast_callable, Wrapper
    91 
    92 include "stdsage.pxi"
    93 
    94 cdef extern from "Python.h":
    95     int PyInt_AS_LONG(PyObject*)
    96     PyObject* PyTuple_New(Py_ssize_t size)
    97     PyObject* PyTuple_GET_ITEM(PyObject* t, Py_ssize_t index)
    98     void PyTuple_SET_ITEM(PyObject* t, Py_ssize_t index, PyObject* item)
    99     object PyObject_CallObject(PyObject* func, PyObject* args)
    100     PyObject* PyFloat_FromDouble(double d)
    101     void Py_DECREF(PyObject *)
    102 
    103 cdef extern from "math.h":
    104     double sqrt(double)
    105     double pow(double, double)
    106 
    107     double ceil(double)
    108     double floor(double)
    109 
    110     double sin(double)
    111     double cos(double)
    112     double tan(double)
    113    
    114     double asin(double)
    115     double acos(double)
    116     double atan(double)
    117     double atan2(double, double)
    118    
    119     double sinh(double)
    120     double cosh(double)
    121     double tanh(double)
    122    
    123     double asinh(double)
    124     double acosh(double)
    125     double atanh(double)
    126    
    127     double exp(double)
    128     double log(double)
    129     double log10(double)
    130     double log2_ "log2"(double)
    131 
    132 
    133 # This is only needed on Cygwin since log2 is a macro.
    134 # If we don't do this the cygwin GCC gets very confused.
    135 cdef inline double log2(double x):
    136     return log2_(x)
    137 
    138 cdef extern from *:
    139     void* memcpy(void* dst, void* src, size_t len)
    140 
    141 cdef inline int max(int a, int b):
    142     return a if a > b else b
    143 
    144 cdef inline int min(int a, int b):
    145     return a if a < b else b
    146 
    147 cdef enum:
    148 # stack
    149     LOAD_ARG    # push input argument n onto the stack
    150     PUSH_CONST
    151     POP
    152     POP_N
    153     DUP
    154 
    155 # basic arithmetic
    156     ADD
    157     SUB
    158     MUL
    159     DIV
    160     NEG
    161     ABS
    162     INVERT
    163     POW
    164    
    165 # basic comparison
    166     LT
    167     LE
    168     EQ
    169     NE
    170     GT
    171     GE
    172 
    173 # functional
    174     ONE_ARG_FUNC
    175     TWO_ARG_FUNC
    176     PY_FUNC
    177    
    178 
    179 # These two dictionaries are for printable and machine independent representation.
    180 
    181 op_names = {
    182     LOAD_ARG: 'load',
    183     PUSH_CONST: 'push',
    184     POP: 'pop',
    185     POP_N: 'popn',
    186     DUP: 'dup',
    187    
    188     ADD: 'add',
    189     SUB: 'sub',
    190     MUL: 'mul',
    191     DIV: 'div',
    192     NEG: 'neg',
    193     ABS: 'abs',
    194     INVERT: 'invert',
    195     POW: 'pow',
    196 
    197 
    198     LT: 'lt',
    199     LE: 'le',
    200     EQ: 'eq',
    201     NE: 'ne',
    202     GT: 'gt',
    203     GE: 'ge',
    204 
    205 
    206     ONE_ARG_FUNC: 'call',
    207     TWO_ARG_FUNC: 'call',
    208     PY_FUNC: 'py_call',
    209 }
    210 
    211 cfunc_names = {
    212     <size_t>&sqrt: 'sqrt',
    213     <size_t>&pow: 'pow',
    214    
    215     <size_t>&ceil: 'ceil',
    216     <size_t>&floor: 'floor',
    217    
    218     <size_t>&sin: 'sin',
    219     <size_t>&cos: 'cos',
    220     <size_t>&tan: 'tan',
    221    
    222     <size_t>&asin: 'asin',
    223     <size_t>&atan: 'atan',
    224     <size_t>&atan2: 'atan2',
    225    
    226     <size_t>&sinh: 'sinh',
    227     <size_t>&cosh: 'cosh',
    228     <size_t>&tanh: 'tanh',
    229 
    230     <size_t>&asinh: 'asinh',
    231     <size_t>&acosh: 'acosh',
    232     <size_t>&atanh: 'atanh',
    233 
    234     <size_t>&exp: 'exp',
    235     <size_t>&log: 'log',
    236     <size_t>&log2: 'log2',
    237     <size_t>&log10: 'log10',
    238 
    239 }
    240 
    241 cdef reverse_map(m):
    242     r = {}
    243     for key, value in m.iteritems():
    244         r[value] = key
    245     return r
    246 
    247 # With all the functionality around the op struct, perhaps there should be
    248 # a wrapper class, though we still wish to operate on pure structs for speed.
    249 
    250 cdef op_to_string(fast_double_op op):
    251     s = op_names[op.type]
    252     if op.type in [LOAD_ARG, POP_N]:
    253         s += " %s" % op.params.n
    254     elif op.type == PUSH_CONST:
    255         s += " %s" % op.params.c
    256     elif op.type in [ONE_ARG_FUNC, TWO_ARG_FUNC]:
    257         try:
    258             cname = cfunc_names[<size_t>op.params.func]
    259         except KeyError:
    260             cname = "0x%x" % <size_t>op.params.func
    261         s += " %s(%s)" % (cname, 1 if op.type == ONE_ARG_FUNC else 2)
    262     elif op.type == PY_FUNC:
    263         n, func = <object>(op.params.func)
    264         s += " %s(%s)" % (func, n)
    265     return s
    266    
    267 cdef op_to_tuple(fast_double_op op):
    268     s = op_names[op.type]
    269     if op.type in [LOAD_ARG, POP_N]:
    270         param = op.params.n
    271     elif op.type == PUSH_CONST:
    272         param = op.params.c
    273     elif op.type in [ONE_ARG_FUNC, TWO_ARG_FUNC]:
    274         param_count = 1 if op.type == ONE_ARG_FUNC else 2
    275         try:
    276             param = param_count, cfunc_names[<size_t>op.params.func]
    277         except KeyError:
    278             raise ValueError, "Unknown C function: 0x%x" % <size_t>op.params.func
    279     elif op.type == PY_FUNC:
    280         param = <object>(op.params.func)
    281     else:
    282         param = None
    283     if param is None:
    284         return (s,)
    285     else:
    286         return s, param
    287        
    288 def _unpickle_FastDoubleFunc(nargs, max_height, op_list):
    289     cdef FastDoubleFunc self = PY_NEW(FastDoubleFunc)
    290     self.nops = len(op_list)
    291     self.nargs = nargs
    292     self.max_height = max_height
    293     self.ops = <fast_double_op *>sage_malloc(sizeof(fast_double_op) * self.nops)
    294     self.allocate_stack()
    295     cfunc_addresses = reverse_map(cfunc_names)
    296     op_enums = reverse_map(op_names)
    297     cdef size_t address
    298     cdef int i = 0, type
    299     for op in op_list:
    300         self.ops[i].type = type = op_enums[op[0]]
    301         if type in [LOAD_ARG, POP_N]:
    302             self.ops[i].params.n = op[1]
    303         elif type == PUSH_CONST:
    304             self.ops[i].params.c = op[1]
    305         elif type in [ONE_ARG_FUNC, TWO_ARG_FUNC]:
    306             param_count, cfunc = op[1]
    307             address = cfunc_addresses[cfunc]
    308             self.ops[i].params.func = <void *>address
    309             self.ops[i].type = ['', ONE_ARG_FUNC, TWO_ARG_FUNC][param_count]
    310         elif type == PY_FUNC:
    311             if self.py_funcs is None:
    312                 self.py_funcs = op[1]
    313             else:
    314                 self.py_funcs = self.py_funcs + (op[1],)
    315             self.ops[i].params.func = <void *>op[1]
    316         i += 1
    317     return self
    318    
    319    
    320 # This is where we wish we had case statements...
    321 # It looks like gcc might be smart enough to figure it out.
    322 cdef inline int process_op(fast_double_op op, double* stack, double* argv, int top) except -2:
    323 
    324 #    print [stack[i] for i from 0 <= i <= top], ':', op.type
    325 
    326     cdef int i, n
    327     cdef PyObject* py_args
    328    
    329     # We have to do some trickery because Pyrex disallows function pointer casts
    330     # This will be removed in a future version of Cython.
    331     cdef double (*f)(double)
    332     cdef void** fp = <void **>&f
    333     cdef double (*ff)(double, double)
    334     cdef void** ffp = <void **>&ff
    335 
    336     if op.type == LOAD_ARG:
    337         stack[top+1] = argv[op.params.n]
    338         return top+1
    339        
    340     elif op.type == PUSH_CONST:
    341         stack[top+1] = op.params.c
    342         return top+1
    343        
    344     elif op.type == POP:
    345         return top-1
    346        
    347     elif op.type == POP_N:
    348         return top-op.params.n
    349        
    350     elif op.type == DUP:
    351         stack[top+1] = stack[top]
    352         return top+1
    353 
    354     elif op.type == ADD:
    355         stack[top-1] += stack[top]
    356         return top-1
    357 
    358     elif op.type == SUB:
    359         stack[top-1] -= stack[top]
    360         return top-1
    361 
    362     elif op.type == MUL:
    363         stack[top-1] *= stack[top]
    364         return top-1
    365 
    366     elif op.type == DIV:
    367         stack[top-1] /= stack[top]
    368         return top-1
    369        
    370     elif op.type == NEG:
    371         stack[top] = -stack[top]
    372         return top
    373        
    374     elif op.type == ABS:
    375         if stack[top] < 0:
    376             stack[top] = -stack[top]
    377         return top
    378        
    379     elif op.type == INVERT:
    380         stack[top] = 1/stack[top]
    381         return top
    382        
    383     elif op.type == POW:
    384         if stack[top-1] < 0 and stack[top] != floor(stack[top]):
    385             raise ValueError, "negative number to a fractional power not real"
    386         stack[top-1] = pow(stack[top-1], stack[top])
    387         return top-1
    388        
    389     elif op.type == LT:
    390         stack[top-1] = 1.0 if stack[top-1] < stack[top] else 0.0
    391         return top-1
    392 
    393     elif op.type == LE:
    394         stack[top-1] = 1.0 if stack[top-1] <= stack[top] else 0.0
    395         return top-1
    396 
    397     elif op.type == EQ:
    398         stack[top-1] = 1.0 if stack[top-1] == stack[top] else 0.0
    399         return top-1
    400 
    401     elif op.type == NE:
    402         stack[top-1] = 1.0 if stack[top-1] != stack[top] else 0.0
    403         return top-1
    404 
    405     elif op.type == GT:
    406         stack[top-1] = 1.0 if stack[top-1] > stack[top] else 0.0
    407         return top-1
    408 
    409     elif op.type == GE:
    410         stack[top-1] = 1.0 if stack[top-1] >= stack[top] else 0.0
    411         return top-1
    412 
    413     elif op.type == ONE_ARG_FUNC:
    414         fp[0] = op.params.func
    415         stack[top] = f(stack[top])
    416         return top
    417 
    418     elif op.type == TWO_ARG_FUNC:
    419         ffp[0] = op.params.func
    420         stack[top-1] = ff(stack[top-1], stack[top])
    421         return top-1
    422 
    423     elif op.type == PY_FUNC:
    424         # Even though it's python, optimize this because it'll be used often...
    425         # We also want to avoid cluttering the header and footer
    426         # of this function Python variables bring.
    427         n = PyInt_AS_LONG(PyTuple_GET_ITEM(op.params.func, 0))
    428         top = top - n + 1
    429         py_args = PyTuple_New(n)
    430         for i from 0 <= i < n:
    431             PyTuple_SET_ITEM(py_args, i, PyFloat_FromDouble(stack[top+i]))
    432         stack[top] = PyObject_CallObject(PyTuple_GET_ITEM(op.params.func, 1), py_args)
    433         Py_DECREF(py_args)
    434         return top
    435        
    436     raise RuntimeError, "Bad op code %s" % op.type
    437 
    438 
    439 cdef class FastDoubleFunc:
    440     """
    441     This class is for fast evaluation of algebraic expressions over
    442     the real numbers (e.g. for plotting). It represents an expression
    443     as a stack-based series of operations.
    444    
    445     EXAMPLES:
    446         sage: from sage.ext.fast_eval import FastDoubleFunc
    447         sage: f = FastDoubleFunc('const', 1.5) # the constant function
    448         sage: f()
    449         1.5
    450         sage: g = FastDoubleFunc('arg', 0) # the first argument
    451         sage: g(5)
    452         5.0
    453         sage: h = f+g
    454         sage: h(17)
    455         18.5
    456         sage: h = h.sin()
    457         sage: h(pi/2-1.5)
    458         1.0
    459         sage: h.is_pure_c()
    460         True
    461         sage: list(h)
    462         ['push 1.5', 'load 0', 'add', 'call sin(1)']
    463        
    464     We can wrap Python functions too:
    465         sage: h = FastDoubleFunc('callable', lambda x,y: x*x*x - y, g, f)
    466         sage: h(10)
    467         998.5
    468         sage: h.is_pure_c()
    469         False
    470         sage: list(h)        # random address
    471         ['load 0', 'push 1.5', 'py_call <function <lambda> at 0x9fedf70>(2)']
    472        
    473     Here's a more complicated expression:
    474         sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg
    475         sage: a = fast_float_constant(1.5)
    476         sage: b = fast_float_constant(3.14)
    477         sage: c = fast_float_constant(7)
    478         sage: x = fast_float_arg(0)
    479         sage: y = fast_float_arg(1)
    480         sage: f = a*x^2 + b*x + c - y/sqrt(sin(y)^2+a)
    481         sage: f(2,3)
    482         16.846610528508116
    483         sage: f.max_height
    484         4
    485         sage: f.is_pure_c()
    486         True
    487         sage: list(f)
    488         ['push 1.5', 'load 0', 'dup', 'mul', 'mul', 'push 3.14', 'load 0', 'mul', 'add', 'push 7.0', 'add', 'load 1', 'load 1', 'call sin(1)', 'dup', 'mul', 'push 1.5', 'add', 'call sqrt(1)', 'div', 'sub']
    489        
    490    
    491     AUTHOR:
    492         -- Robert Bradshaw
    493     """
    494     def __init__(self, type, param, *args):
    495 
    496         cdef FastDoubleFunc arg
    497         cdef int i
    498        
    499         if type == 'arg':
    500             self.nargs = param+1
    501             self.nops = 1
    502             self.max_height = 1
    503             self.ops = <fast_double_op *>sage_malloc(sizeof(fast_double_op))
    504             self.ops[0].type = LOAD_ARG
    505             self.ops[0].params.n = param
    506            
    507         elif type == 'const':
    508             self.nargs = 0
    509             self.nops = 1
    510             self.max_height = 1
    511             self.ops = <fast_double_op *>sage_malloc(sizeof(fast_double_op))
    512             self.ops[0].type = PUSH_CONST
    513             self.ops[0].params.c = param
    514            
    515         elif type == 'callable':
    516             py_func = len(args), param
    517             self.py_funcs = (py_func,) # just so it doesn't get garbage collected
    518             self.nops = 1
    519             self.nargs = 0
    520             for i from 0 <= i < len(args):
    521                 a = args[i]
    522                 if not isinstance(a, FastDoubleFunc):
    523                      a = FastDoubleFunc('const', a)
    524                      args = args[:i] + (a,) + args[i+1:]
    525                 arg = a
    526                 self.nops += arg.nops
    527                 if arg.py_funcs is not None:
    528                     self.py_funcs += arg.py_funcs
    529                 self.nargs = max(self.nargs, arg.nargs)
    530                 self.max_height = max(self.max_height, arg.max_height+i)
    531             self.ops = <fast_double_op *>sage_malloc(sizeof(fast_double_op) * self.nops)
    532             if self.ops == NULL:
    533                 raise MemoryError
    534             i = 0
    535             for arg in args:
    536                 memcpy(self.ops + i, arg.ops, sizeof(fast_double_op) * arg.nops)
    537                 i += arg.nops
    538             self.ops[self.nops-1].type = PY_FUNC
    539             self.ops[self.nops-1].params.func = <void *>py_func
    540            
    541         else:
    542             raise ValueError, "Unknown operation: %s" % type
    543            
    544         self.allocate_stack()
    545            
    546            
    547     cdef int allocate_stack(FastDoubleFunc self) except -1:
    548         self.argv = <double*>sage_malloc(sizeof(double) * self.nargs)
    549         if self.argv == NULL:
    550             raise MemoryError
    551         self.stack = <double*>sage_malloc(sizeof(double) * self.max_height)
    552         if self.stack == NULL:
    553             raise MemoryError
    554            
    555     def __dealloc__(self):
    556         if self.ops:
    557             sage_free(self.ops)
    558         if self.stack:
    559             sage_free(self.stack)
    560         if self.argv:
    561             sage_free(self.argv)
    562            
    563     def __reduce__(self):
    564         """
    565         TESTS:
    566             sage: from sage.ext.fast_eval import fast_float_arg, fast_float_func
    567             sage: f = fast_float_arg(0).sin() * 10 + fast_float_func(hash, fast_float_arg(1))
    568             sage: loads(dumps(f)) == f
    569             True
    570         """
    571         L = [op_to_tuple(self.ops[i]) for i from 0 <= i < self.nops]
    572         return _unpickle_FastDoubleFunc, (self.nargs, self.max_height, L)
    573        
    574     def __cmp__(self, other):
    575         """
    576         Two functions are considered equal if they represent the same
    577         exact sequence of operations.
    578        
    579         TESTS:
    580             sage: from sage.ext.fast_eval import fast_float_arg
    581             sage: fast_float_arg(0) == fast_float_arg(0)
    582             True
    583             sage: fast_float_arg(0) == fast_float_arg(1)
    584             False
    585             sage: fast_float_arg(0) == fast_float_arg(0).sin()
    586             False
    587         """
    588         cdef int c, i
    589         cdef FastDoubleFunc left, right
    590         try:
    591             left, right = self, other
    592             c = cmp((left.nargs, left.nops, left.max_height),
    593                     (right.nargs, right.nops, right.max_height))
    594             if c != 0:
    595                 return c
    596             for i from 0 <= i < self.nops:
    597                 if left.ops[i].type != right.ops[i].type:
    598                     return cmp(left.ops[i].type, right.ops[i].type)
    599             for i from 0 <= i < self.nops:
    600                 c = cmp(op_to_tuple(left.ops[i]), op_to_tuple(right.ops[i]))
    601                 if c != 0:
    602                     return c
    603             return c
    604         except TypeError:
    605             return cmp(type(self), type(other))
    606    
    607     def __call__(FastDoubleFunc self, *args):
    608         """
    609         EXAMPLES:
    610             sage: from sage.ext.fast_eval import fast_float_arg
    611             sage: f = fast_float_arg(2)
    612             sage: f(0,1,2,3)
    613             2.0
    614             sage: f(10)
    615             Traceback (most recent call last):
    616             ...
    617             TypeError: Wrong number of arguments (need at least 3, got 1)
    618             sage: f('blah', 1, 2, 3)
    619             Traceback (most recent call last):
    620             ...
    621             TypeError: a float is required
    622         """
    623         if len(args) < self.nargs:
    624             raise TypeError, "Wrong number of arguments (need at least %s, got %s)" % (self.nargs, len(args))
    625         cdef int i = 0
    626         for i from 0 <= i < self.nargs:
    627             self.argv[i] = args[i]
    628         res = self._call_c(self.argv)
    629         return res
    630        
    631     cdef double _call_c(FastDoubleFunc self, double* argv) except? -2:
    632         # The caller must assure that argv has length at least self.nargs
    633         # The bulk of this function is in the (inlined) function process_op.
    634         cdef int i, top = -1
    635         for i from 0 <= i < self.nops:
    636             top = process_op(self.ops[i], self.stack, argv, top)
    637         cdef double res = self.stack[0]
    638         return res
    639        
    640     def _fast_float_(self, *vars):
    641         r"""
    642         Returns \code{self} if there are enough arguments, otherwise raises a TypeError.
    643        
    644         EXAMPLES:
    645             sage: from sage.ext.fast_eval import fast_float_arg
    646             sage: f = fast_float_arg(1)
    647             sage: f._fast_float_('x','y') is f
    648             True
    649             sage: f._fast_float_('x') is f
    650             Traceback (most recent call last):
    651             ...
    652             TypeError: Needs at least 2 arguments (1 provided)
    653         """
    654         if self.nargs > len(vars):
    655             raise TypeError, "Needs at least %s arguments (%s provided)" % (self.nargs, len(vars))
    656         return self
    657        
    658     def op_list(self):
    659         """
    660         Returns a list of string representations of the
    661         operations that make up this expression.
    662        
    663         Python and C function calls may be only available by function pointer addresses.
    664        
    665         EXAMPLES:
    666             sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg
    667             sage: a = fast_float_constant(17)
    668             sage: x = fast_float_arg(0)
    669             sage: a.op_list()
    670             ['push 17.0']
    671             sage: x.op_list()
    672             ['load 0']
    673             sage: (a*x).op_list()
    674             ['push 17.0', 'load 0', 'mul']
    675             sage: (a+a*x^2).sqrt().op_list()
    676             ['push 17.0', 'push 17.0', 'load 0', 'dup', 'mul', 'mul', 'add', 'call sqrt(1)']
    677         """
    678         cdef int i
    679         return [op_to_string(self.ops[i]) for i from 0 <= i < self.nops]
    680        
    681     def __iter__(self):
    682         """
    683         Returns the list of operations of self.
    684        
    685         EXAMPLES:
    686             sage: from sage.ext.fast_eval import fast_float_arg
    687             sage: f = fast_float_arg(0)*2 + 3
    688             sage: list(f)
    689             ['load 0', 'push 2.0', 'mul', 'push 3.0', 'add']
    690         """
    691         return iter(self.op_list())
    692        
    693     cpdef bint is_pure_c(self):
    694         """
    695         Returns True if this function can be evaluated without
    696         any python calls (at any level).
    697        
    698         EXAMPLES:
    699             sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg, fast_float_func
    700             sage: fast_float_constant(2).is_pure_c()
    701             True
    702             sage: fast_float_arg(2).sqrt().sin().is_pure_c()
    703             True
    704             sage: fast_float_func(lambda _: 2).is_pure_c()
    705             False
    706         """
    707         cdef int i
    708         for i from 0 <= i < self.nops:
    709             if self.ops[i].type == PY_FUNC:
    710                 return 0
    711         return 1
    712        
    713     def python_calls(self):
    714         """
    715         Returns a list of all python calls used by function.
    716        
    717         EXAMPLES:
    718             sage: from sage.ext.fast_eval import fast_float_func, fast_float_arg
    719             sage: x = fast_float_arg(0)
    720             sage: f = fast_float_func(hash, sqrt(x))
    721             sage: f.op_list()
    722             ['load 0', 'call sqrt(1)', 'py_call <built-in function hash>(1)']
    723             sage: f.python_calls()
    724             [<built-in function hash>]
    725         """
    726         L = []
    727         cdef int i
    728         for i from 0 <= i < self.nops:
    729             if self.ops[i].type == PY_FUNC:
    730                 L.append((<object>self.ops[i].params.func)[1])
    731         return L
    732        
    733     ###################################################################
    734     #   Basic Arithmetic
    735     ###################################################################
    736        
    737     def __add__(left, right):
    738         """
    739         EXAMPLES:
    740             sage: from sage.ext.fast_eval import fast_float_arg
    741             sage: f = fast_float_arg(0) + fast_float_arg(1)
    742             sage: f(3,4)
    743             7.0
    744         """
    745         return binop(left, right, ADD)
    746        
    747     def __sub__(left, right):
    748         """
    749         EXAMPLES:
    750             sage: from sage.ext.fast_eval import fast_float_arg
    751             sage: f = fast_float_arg(0) - fast_float_arg(2)
    752             sage: f(3,4,5)
    753             -2.0
    754         """
    755         return binop(left, right, SUB)
    756        
    757     def __mul__(left, right):
    758         """
    759         EXAMPLES:
    760             sage: from sage.ext.fast_eval import fast_float_arg
    761             sage: f = fast_float_arg(0) * 2
    762             sage: f(17)
    763             34.0
    764         """
    765         return binop(left, right, MUL)
    766        
    767     def __div__(left, right):
    768         """
    769         EXAMPLES:
    770             sage: from sage.ext.fast_eval import fast_float_arg
    771             sage: f = fast_float_arg(0) / 7
    772             sage: f(14)
    773             2.0
    774         """
    775         return binop(left, right, DIV)
    776        
    777     def __pow__(FastDoubleFunc left, right, dummy):
    778         """
    779         EXAMPLES:
    780             sage: from sage.ext.fast_eval import FastDoubleFunc
    781             sage: f = FastDoubleFunc('arg', 0)^2
    782             sage: f(2)
    783             4.0
    784             sage: f = FastDoubleFunc('arg', 0)^4
    785             sage: f(2)
    786             16.0
    787             sage: f = FastDoubleFunc('arg', 0)^-3
    788             sage: f(2)
    789             0.125
    790             sage: f = FastDoubleFunc('arg', 0)^FastDoubleFunc('arg', 1)
    791             sage: f(5,3)
    792             125.0
    793        
    794         TESTS:
    795             sage: var('a,b')
    796             (a, b)
    797             sage: ff = (a^b)._fast_float_(a,b)
    798             sage: ff(2, 9)
    799             512.0
    800             sage: ff(-2, 9)
    801             -512.0
    802             sage: ff(-2, 9.1)
    803             Traceback (most recent call last):
    804             ...
    805             ValueError: negative number to a fractional power not real
    806         """
    807         if isinstance(right, FastDoubleFunc) and right.nargs == 0:
    808             right = float(right)
    809         if not isinstance(right, FastDoubleFunc):
    810             if right == int(float(right)):
    811                 if right == 1:
    812                     return left
    813                 elif right == 2:
    814                     return left.unop(DUP).unop(MUL)
    815                 elif right == 3:
    816                     return left.unop(DUP).unop(DUP).unop(MUL).unop(MUL)
    817                 elif right == 4:
    818                     return left.unop(DUP).unop(MUL).unop(DUP).unop(MUL)
    819                 elif right < 0:
    820                     return (~left)**(-right)
    821             right = FastDoubleFunc('const', right)
    822         cdef FastDoubleFunc feval = binop(left, right, POW)
    823         return feval
    824        
    825     def __neg__(FastDoubleFunc self):
    826         """
    827         EXAMPLE:
    828             sage: from sage.ext.fast_eval import fast_float_arg
    829             sage: f = -fast_float_arg(0)
    830             sage: f(3.5)
    831             -3.5
    832         """
    833         return self.unop(NEG)
    834        
    835     def __abs__(FastDoubleFunc self):
    836         """
    837         EXAMPLE:
    838             sage: from sage.ext.fast_eval import fast_float_arg
    839             sage: f = abs(fast_float_arg(0))
    840             sage: f(-3)
    841             3.0
    842         """
    843         return self.unop(ABS)
    844        
    845     def __float__(self):
    846         """
    847         EXAMPLES:
    848             sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg
    849             sage: ff = fast_float_constant(17)
    850             sage: float(ff)
    851             17.0
    852             sage: ff = fast_float_constant(17) - fast_float_constant(2)^2
    853             sage: float(ff)
    854             13.0
    855             sage: ff = fast_float_constant(17) - fast_float_constant(2)^2 + fast_float_arg(1)
    856             sage: float(ff)
    857             Traceback (most recent call last):
    858             ...
    859             TypeError: Not a constant.
    860         """
    861         if self.nargs == 0:
    862             return self._call_c(NULL)
    863         else:
    864             raise TypeError, "Not a constant."
    865        
    866     def abs(FastDoubleFunc self):
    867         """
    868         EXAMPLE:
    869             sage: from sage.ext.fast_eval import fast_float_arg
    870             sage: f = fast_float_arg(0).abs()
    871             sage: f(3)
    872             3.0
    873         """
    874         return self.unop(ABS)
    875        
    876     def __invert__(FastDoubleFunc self):
    877         """
    878         EXAMPLE:
    879             sage: from sage.ext.fast_eval import fast_float_arg
    880             sage: f = ~fast_float_arg(0)
    881             sage: f(4)
    882             0.25
    883         """
    884         return self.unop(INVERT)
    885        
    886     def sqrt(self):
    887         """
    888         EXAMPLE:
    889             sage: from sage.ext.fast_eval import fast_float_arg
    890             sage: f = fast_float_arg(0).sqrt()
    891             sage: f(4)
    892             2.0
    893         """
    894         return self.cfunc(&sqrt)
    895        
    896     ###################################################################
    897     #   Basic Comparison
    898     ###################################################################
    899 
    900     def _richcmp_(left, right, op):
    901         """
    902         Compare left and right.
    903         EXAMPLES:
    904             sage: from sage.ext.fast_eval import fast_float_arg
    905             sage: import operator
    906             sage: f = fast_float_arg(0)._richcmp_(2, operator.lt)
    907             sage: [f(i) for i in (1..3)]
    908             [1.0, 0.0, 0.0]
    909             sage: f = fast_float_arg(0)._richcmp_(2, operator.le)
    910             sage: [f(i) for i in (1..3)]
    911             [1.0, 1.0, 0.0]
    912             sage: f = fast_float_arg(0)._richcmp_(2, operator.eq)
    913             sage: [f(i) for i in (1..3)]
    914             [0.0, 1.0, 0.0]
    915             sage: f = fast_float_arg(0)._richcmp_(2, operator.ne)
    916             sage: [f(i) for i in (1..3)]
    917             [1.0, 0.0, 1.0]
    918             sage: f = fast_float_arg(0)._richcmp_(2, operator.ge)
    919             sage: [f(i) for i in (1..3)]
    920             [0.0, 1.0, 1.0]
    921             sage: f = fast_float_arg(0)._richcmp_(2, operator.gt)
    922             sage: [f(i) for i in (1..3)]
    923             [0.0, 0.0, 1.0]
    924         """
    925         import operator
    926         if op == operator.lt:  #<
    927             return binop(left, right, LT)
    928         elif op == operator.eq: #==
    929             return binop(left, right, EQ)
    930         elif op == operator.gt: #>
    931             return binop(left, right, GT)
    932         elif op == operator.le: #<=
    933             return binop(left, right, LE)
    934         elif op == operator.ne: #!=
    935             return binop(left, right, NE)
    936         elif op == operator.ge: #>=
    937             return binop(left, right, GE)
    938 
    939 
    940     ###################################################################
    941     #   Exponential and log
    942     ###################################################################
    943        
    944     def log(self, base=None):
    945         """
    946         EXAMPLE:
    947             sage: from sage.ext.fast_eval import fast_float_arg
    948             sage: f = fast_float_arg(0).log()
    949             sage: f(2)
    950             0.693147180559945...
    951             sage: f = fast_float_arg(0).log(2)
    952             sage: f(2)
    953             1.0
    954             sage: f = fast_float_arg(0).log(3)
    955             sage: f(9)
    956             2.0
    957         """
    958         if base is None:
    959             return self.cfunc(&log)
    960         elif base == 2:
    961             return self.cfunc(&log2)
    962         elif base == 10:
    963             return self.cfunc(&log10)
    964         else:
    965             try:
    966                 base = fast_float_constant(log(float(base)))
    967             except TypeError, e:
    968                 base = fast_float(base.log())
    969             return binop(self.cfunc(&log), base, DIV)
    970        
    971     def exp(self):
    972         """
    973         EXAMPLE:
    974             sage: from sage.ext.fast_eval import fast_float_arg
    975             sage: f = fast_float_arg(0).exp()
    976             sage: f(1)
    977             2.718281828459045...
    978             sage: f(100)
    979             2.6881171418161356e+43
    980         """
    981         return self.cfunc(&exp)
    982        
    983     ###################################################################
    984     #   Rounding
    985     ###################################################################
    986 
    987     def ceil(self):
    988         """
    989         EXAMPLE:
    990             sage: from sage.ext.fast_eval import fast_float_arg
    991             sage: f = fast_float_arg(0).ceil()
    992             sage: f(1.5)
    993             2.0
    994             sage: f(-1.5)
    995             -1.0
    996         """
    997         return self.cfunc(&ceil)
    998        
    999     def floor(self):
    1000         """
    1001         EXAMPLE:
    1002             sage: from sage.ext.fast_eval import fast_float_arg
    1003             sage: f = fast_float_arg(0).floor()
    1004             sage: f(11.5)
    1005             11.0
    1006             sage: f(-11.5)
    1007             -12.0
    1008         """
    1009         return self.cfunc(&floor)
    1010        
    1011     ###################################################################
    1012     #   Trigonometric
    1013     ###################################################################
    1014 
    1015     def sin(self):
    1016         """
    1017         EXAMPLE:
    1018             sage: from sage.ext.fast_eval import fast_float_arg
    1019             sage: f = fast_float_arg(0).sin()
    1020             sage: f(pi/2)
    1021             1.0
    1022         """
    1023         return self.cfunc(&sin)
    1024        
    1025     def cos(self):
    1026         """
    1027         EXAMPLE:
    1028             sage: from sage.ext.fast_eval import fast_float_arg
    1029             sage: f = fast_float_arg(0).cos()
    1030             sage: f(0)
    1031             1.0
    1032         """
    1033         return self.cfunc(&cos)
    1034        
    1035     def tan(self):
    1036         """
    1037         EXAMPLE:
    1038             sage: from sage.ext.fast_eval import fast_float_arg
    1039             sage: f = fast_float_arg(0).tan()
    1040             sage: f(pi/3)
    1041             1.73205080756887...
    1042         """
    1043         return self.cfunc(&tan)
    1044        
    1045     def csc(self):
    1046         """
    1047         EXAMPLE:
    1048             sage: from sage.ext.fast_eval import fast_float_arg
    1049             sage: f = fast_float_arg(0).csc()
    1050             sage: f(pi/2)
    1051             1.0
    1052         """
    1053         return ~self.sin()
    1054        
    1055     def sec(self):
    1056         """
    1057         EXAMPLE:
    1058             sage: from sage.ext.fast_eval import fast_float_arg
    1059             sage: f = fast_float_arg(0).sec()
    1060             sage: f(pi)
    1061             -1.0
    1062         """
    1063         return ~self.cos()
    1064        
    1065     def cot(self):
    1066         """
    1067         EXAMPLE:
    1068             sage: from sage.ext.fast_eval import fast_float_arg
    1069             sage: f = fast_float_arg(0).cot()
    1070             sage: f(pi/4)
    1071             1.0...
    1072         """
    1073         return ~self.tan()
    1074        
    1075     def arcsin(self):
    1076         """
    1077         EXAMPLE:
    1078             sage: from sage.ext.fast_eval import fast_float_arg
    1079             sage: f = fast_float_arg(0).arcsin()
    1080             sage: f(0.5)
    1081             0.523598775598298...
    1082         """
    1083         return self.cfunc(&asin)
    1084        
    1085     def arccos(self):
    1086         """
    1087         EXAMPLE:
    1088             sage: from sage.ext.fast_eval import fast_float_arg
    1089             sage: f = fast_float_arg(0).arccos()
    1090             sage: f(sqrt(3)/2)
    1091             0.5235987755982989...
    1092         """
    1093         return self.cfunc(&acos)
    1094        
    1095     def arctan(self):
    1096         """
    1097         EXAMPLE:
    1098             sage: from sage.ext.fast_eval import fast_float_arg
    1099             sage: f = fast_float_arg(0).arctan()
    1100             sage: f(1)
    1101             0.785398163397448...
    1102         """
    1103         return self.cfunc(&atan)
    1104        
    1105     ###################################################################
    1106     #   Hyperbolic
    1107     ###################################################################
    1108 
    1109     def sinh(self):
    1110         """
    1111         EXAMPLE:
    1112             sage: from sage.ext.fast_eval import fast_float_arg
    1113             sage: f = fast_float_arg(0).sinh()
    1114             sage: f(log(2))
    1115             0.75
    1116         """
    1117         return self.cfunc(&sinh)
    1118        
    1119     def cosh(self):
    1120         """
    1121         EXAMPLE:
    1122             sage: from sage.ext.fast_eval import fast_float_arg
    1123             sage: f = fast_float_arg(0).cosh()
    1124             sage: f(log(2))
    1125             1.25
    1126         """
    1127         return self.cfunc(&cosh)
    1128        
    1129     def tanh(self):
    1130         """
    1131         EXAMPLE:
    1132             sage: from sage.ext.fast_eval import fast_float_arg
    1133             sage: f = fast_float_arg(0).tanh()
    1134             sage: f(0)
    1135             0.0
    1136         """
    1137         return self.cfunc(&tanh)
    1138        
    1139     def arcsinh(self):
    1140         """
    1141         EXAMPLE:
    1142             sage: from sage.ext.fast_eval import fast_float_arg
    1143             sage: f = fast_float_arg(0).arcsinh()
    1144             sage: f(sinh(5))
    1145             5.0
    1146         """
    1147         return self.cfunc(&asinh)
    1148        
    1149     def arccosh(self):
    1150         """
    1151         EXAMPLE:
    1152             sage: from sage.ext.fast_eval import fast_float_arg
    1153             sage: f = fast_float_arg(0).arccosh()
    1154             sage: f(cosh(5))
    1155             5.0
    1156         """
    1157         return self.cfunc(&acosh)
    1158        
    1159     def arctanh(self):
    1160         """
    1161         EXAMPLE:
    1162             sage: from sage.ext.fast_eval import fast_float_arg
    1163             sage: f = fast_float_arg(0).arctanh()
    1164             sage: abs(f(tanh(0.5)) - 0.5) < 0.0000001
    1165             True
    1166         """
    1167         return self.cfunc(&atanh)
    1168        
    1169     cdef FastDoubleFunc cfunc(FastDoubleFunc self, void* func):
    1170         cdef FastDoubleFunc feval = self.unop(ONE_ARG_FUNC)
    1171         feval.ops[feval.nops - 1].params.func = func
    1172         feval.allocate_stack()
    1173         return feval
    1174        
    1175     ###################################################################
    1176     #   Utility functions
    1177     ###################################################################
    1178 
    1179     cdef FastDoubleFunc unop(FastDoubleFunc self, char type):
    1180         cdef FastDoubleFunc feval = PY_NEW(FastDoubleFunc)
    1181         feval.nargs = self.nargs
    1182         feval.nops = self.nops + 1
    1183         feval.max_height = self.max_height
    1184         if type == DUP:
    1185             feval.max_height += 1
    1186         feval.ops = <fast_double_op *>sage_malloc(sizeof(fast_double_op) * feval.nops)
    1187         memcpy(feval.ops, self.ops, sizeof(fast_double_op) * self.nops)
    1188         feval.ops[feval.nops - 1].type = type
    1189         feval.py_funcs = self.py_funcs
    1190         feval.allocate_stack()
    1191         return feval
    1192 
    1193 cdef FastDoubleFunc binop(_left, _right, char type):
    1194     r"""
    1195     Returns a function that calculates left and right on the stack, leaving
    1196     their results on the top, and then calls operation \code{type}.
    1197    
    1198     EXAMPLES:
    1199         sage: from sage.ext.fast_eval import fast_float_arg
    1200         sage: f = fast_float_arg(1)
    1201         sage: g = fast_float_arg(2) * 11
    1202         sage: f.op_list()
    1203         ['load 1']
    1204         sage: g.op_list()
    1205         ['load 2', 'push 11.0', 'mul']
    1206         sage: (f+g).op_list()
    1207         ['load 1', 'load 2', 'push 11.0', 'mul', 'add']
    1208        
    1209     Correctly calculates the maximum stack heights and number of arguments:
    1210         sage: f.max_height
    1211         1
    1212         sage: g.max_height
    1213         2
    1214         sage: (f+g).max_height
    1215         3
    1216         sage: (g+f).max_height
    1217         2
    1218        
    1219         sage: f.nargs
    1220         2
    1221         sage: g.nargs
    1222         3
    1223         sage: (f+g).nargs
    1224         3
    1225     """
    1226     cdef FastDoubleFunc left, right
    1227     try:
    1228         left = _left
    1229     except TypeError:
    1230         left = fast_float(_left)
    1231     try:
    1232         right = _right
    1233     except TypeError:
    1234         right = fast_float(_right)
    1235 
    1236     # In Cython assigning None does NOT raise a TypeError above.
    1237     if left is None or right is None:
    1238         raise TypeError
    1239    
    1240     cdef FastDoubleFunc feval = PY_NEW(FastDoubleFunc)
    1241     feval.nargs = max(left.nargs, right.nargs)
    1242     feval.nops = left.nops + right.nops + 1
    1243     feval.max_height = max(left.max_height, right.max_height+1)
    1244     feval.ops = <fast_double_op *>sage_malloc(sizeof(fast_double_op) * feval.nops)
    1245     memcpy(feval.ops, left.ops, sizeof(fast_double_op) * left.nops)
    1246     memcpy(feval.ops + left.nops, right.ops, sizeof(fast_double_op) * right.nops)
    1247     feval.ops[feval.nops - 1].type = type
    1248     if left.py_funcs is None:
    1249         feval.py_funcs = right.py_funcs
    1250     elif right.py_funcs is None:
    1251         feval.py_funcs = left.py_funcs
    1252     else:
    1253         feval.py_funcs = left.py_funcs + right.py_funcs
    1254     feval.allocate_stack()
    1255     return feval
    1256    
    1257    
    1258 def fast_float_constant(x):
    1259     """
    1260     Return a fast-to-evaluate constant function.
    1261    
    1262     EXAMPLES:
    1263         sage: from sage.ext.fast_eval import fast_float_constant
    1264         sage: f = fast_float_constant(-2.75)
    1265         sage: f()
    1266         -2.75
    1267 
    1268     This is all that goes on under the hood:
    1269         sage: fast_float_constant(pi).op_list()
    1270         ['push 3.14159265359']
    1271     """
    1272     return FastDoubleFunc('const', x)
    1273    
    1274 def fast_float_arg(n):
    1275     """
    1276     Return a fast-to-evaluate argument selector.
    1277    
    1278     INPUT:
    1279         n -- the (zero-indexed) argument to select
    1280    
    1281     EXAMPLES:
    1282         sage: from sage.ext.fast_eval import fast_float_arg
    1283         sage: f = fast_float_arg(0)
    1284         sage: f(1,2)
    1285         1.0
    1286         sage: f = fast_float_arg(1)
    1287         sage: f(1,2)
    1288         2.0
    1289        
    1290     This is all that goes on under the hood:
    1291         sage: fast_float_arg(10).op_list()
    1292         ['load 10']
    1293     """
    1294     return FastDoubleFunc('arg', n)
    1295    
    1296 def fast_float_func(f, *args):
    1297     """
    1298     Returns a wrapper around a python function.
    1299    
    1300     INPUT:
    1301         f -- a callable python object
    1302         args -- a list of FastDoubleFunc inputs
    1303    
    1304     EXAMPLES:
    1305         sage: from sage.ext.fast_eval import fast_float_func, fast_float_arg
    1306         sage: f = fast_float_arg(0)
    1307         sage: g = fast_float_arg(1)
    1308         sage: h = fast_float_func(lambda x,y: x-y, f, g)
    1309         sage: h(5, 10)
    1310         -5.0
    1311 
    1312     This is all that goes on under the hood:
    1313         sage: h.op_list() # random memory address
    1314         ['load 0', 'load 1', 'py_call <function <lambda> at 0xb62b230>(2)']
    1315     """
    1316     return FastDoubleFunc('callable', f, *args)
    1317 
    1318 
    1319 new_fast_float=True
    1320 
    1321 def fast_float(f, *vars, old=None, expect_one_var=False):
    1322     """
    1323     Tries to create a function that evaluates f quickly using
    1324     floating-point numbers, if possible.  There are two implementations
    1325     of fast_float in Sage; by default we use the newer, which is
    1326     slightly faster on most tests.
    1327    
    1328     On failure, returns the input unchanged.
    1329    
    1330     INPUT:
    1331         f    -- an expression
    1332         vars -- the names of the arguments
    1333         old  -- use the original algorithm for fast_float
    1334         expect_one_var -- don't give deprecation warning if vars is
    1335                           omitted, as long as expression has only one var
    1336        
    1337     EXAMPLES:
    1338         sage: from sage.ext.fast_eval import fast_float
    1339         sage: x,y = var('x,y')
    1340         sage: f = fast_float(sqrt(x^2+y^2), 'x', 'y')
    1341         sage: f(3,4)
    1342         5.0
    1343 
    1344     Specifying the argument names is essential, as fast_float objects
    1345     only distinguish between arguments by order.
    1346         sage: f = fast_float(x-y, 'x','y')
    1347         sage: f(1,2)
    1348         -1.0
    1349         sage: f = fast_float(x-y, 'y','x')
    1350         sage: f(1,2)
    1351         1.0
    1352     """
    1353     if old is None:
    1354         old = not new_fast_float
    1355 
    1356     if isinstance(f, (tuple, list)):
    1357         return tuple([fast_float(x, *vars, expect_one_var=expect_one_var) for x in f])
    1358    
    1359     cdef int i
    1360     for i from 0 <= i < len(vars):
    1361         if not PY_TYPE_CHECK(vars[i], str):
    1362             v = str(vars[i])
    1363             # inexact generators display as 1.00..0*x
    1364             if '*' in v:
    1365                 v = v[v.index('*')+1:]
    1366             vars = vars[:i] + (v,) + vars[i+1:]
    1367 
    1368     try:
    1369         if old:
    1370             return f._fast_float_(*vars)
    1371         else:
    1372             return fast_callable(f, vars=vars, domain=float, _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=True, expect_one_var=expect_one_var)
    1373     except AttributeError:
    1374         pass
    1375 
    1376     try:
    1377         return FastDoubleFunc('const', float(f))
    1378     except TypeError:
    1379         pass
    1380 
    1381     try:
    1382         from sage.symbolic.ring import SR
    1383         return fast_float(SR(f), *vars)
    1384     except TypeError:
    1385         pass
    1386 
    1387     if f is None:
    1388         raise TypeError, "no way to make fast_float from None"
    1389        
    1390     return f
    1391 
    1392 def is_fast_float(x):
    1393     return PY_TYPE_CHECK(x, FastDoubleFunc) or PY_TYPE_CHECK(x, Wrapper)
    1394 
  • sage/gsl/integration.pyx

    diff -r 338637719747 -r 33d569c5906f sage/gsl/integration.pyx
    a b  
    2525import sage.plot.plot
    2626import sage.gsl.interpolation
    2727
    28 from sage.ext.fast_eval cimport FastDoubleFunc
     28#from sage.ext.fast_eval cimport FastDoubleFunc
     29
     30from sage.ext.fast_callable cimport Wrapper
    2931
    3032cdef class PyFunctionWrapper:
    3133   cdef object the_function
     
    5860   return value
    5961
    6062
    61 cdef double c_ff(double t, void *params):
    62     return (<FastDoubleFunc>params)._call_c(&t)
     63#cdef double c_ff(double t, void *params):
     64#    return (<FastDoubleFunc>params)._call_c(&t)
    6365
    6466
    6567def numerical_integral(func, a, b=None,
     
    196198   cdef gsl_integration_workspace* W
    197199   W=NULL
    198200   
    199    if not isinstance(func, FastDoubleFunc):
    200         try:
    201             if hasattr(func, 'arguments'):
    202                 vars = func.arguments()
    203             else:
    204                 vars = func.variables()
    205             if len(vars) != 1:
    206                 if len(params) + 1 != len(vars):
    207                     raise ValueError, "Integrand has wrong number of parameters"
    208                 to_sub = dict(zip(vars[1:], params))
    209                 func = func.subs(to_sub)
    210             func = func._fast_float_(str(vars[0]))
    211         except (AttributeError):
    212             pass
     201   # if not isinstance(func, FastDoubleFunc):
     202   #      try:
     203   #          if hasattr(func, 'arguments'):
     204   #              vars = func.arguments()
     205   #          else:
     206   #              vars = func.variables()
     207   #          if len(vars) != 1:
     208   #              if len(params) + 1 != len(vars):
     209   #                  raise ValueError, "Integrand has wrong number of parameters"
     210   #              to_sub = dict(zip(vars[1:], params))
     211   #              func = func.subs(to_sub)
     212   #          func = func._fast_float_(str(vars[0]))
     213   #      except (AttributeError):
     214   #          pass
    213215
    214    if isinstance(func, FastDoubleFunc):
    215         F.function = c_ff
    216         F.params = <void *>func
     216#   if isinstance(func, FastDoubleFunc):
     217#        F.function = c_ff
     218#        F.params = <void *>func
    217219   
    218    elif not isinstance(func, compiled_integrand):
     220   if not isinstance(func, compiled_integrand):
    219221      wrapper = PyFunctionWrapper()
    220222      if not func is None:
    221223         wrapper.the_function = func
  • sage/plot/misc.py

    diff -r 338637719747 -r 33d569c5906f sage/plot/misc.py
    a b  
    1616
    1717from sage.misc.misc import verbose, deprecation
    1818
    19 from sage.ext.fast_eval import fast_float, fast_float_constant, is_fast_float
    20 
     19#from sage.ext.fast_eval import fast_float, fast_float_constant
     20from sage.ext.fast_callable import fast_callable
    2121
    2222def ensure_subs(f):
    2323    if not hasattr(f, 'subs'):
     
    406406    #TODO: raise an error if there is a function/method in funcs that takes more values than we have ranges
    407407
    408408    if return_vars:
    409         return fast_float(funcs, *vars,**options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)], vars
     409        return fast_callable(funcs, vars=vars,domain=float, **options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)], vars
    410410    else:
    411         return fast_float(funcs, *vars,**options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)]
     411        return fast_callable(funcs, vars=vars,domain=float, **options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)]
    412412       
    413413
    414414def unify_arguments(funcs):
  • sage/plot/plot.py

    diff -r 338637719747 -r 33d569c5906f sage/plot/plot.py
    a b  
    364364from math import sin, cos, pi #for polar_plot
    365365from sage.structure.sage_object import SageObject
    366366
    367 from sage.ext.fast_eval import fast_float, fast_float_constant, is_fast_float
     367#from sage.ext.fast_eval import fast_float, fast_float_constant, is_fast_float
    368368
    369369from sage.misc.html import html
    370370
     
    26362636                        fstr = 'min'
    26372637                    msg = "WARNING: You use the built-in function %s for filling. You probably wanted the string '%s'." % (fstr, fstr)
    26382638                    sage.misc.misc.verbose(msg, level=0)
    2639                 if not is_fast_float(fill):
    2640                     fill_f = fast_float(fill, expect_one_var=True)
    2641                 else:
    2642                     fill_f = fill
     2639                    fill_f = fast_callable(fill, expect_one_var=True)
    26432640
    26442641                filldata = generate_plot_points(fill_f, xrange, plot_points, adaptive_tolerance, \
    26452642                                                adaptive_recursion, randomize)
  • sage/plot/plot3d/parametric_plot3d.py

    diff -r 338637719747 -r 33d569c5906f sage/plot/plot3d/parametric_plot3d.py
    a b  
    99from sage.misc.misc import xsrange, srange
    1010from sage.structure.element import is_Vector
    1111
    12 from sage.ext.fast_eval import fast_float, fast_float_constant, is_fast_float
     12#from sage.ext.fast_eval import fast_float, fast_float_constant, is_fast_float
    1313
    1414def parametric_plot3d(f, urange, vrange=None, plot_points="automatic", boundary_style=None, **kwds):
    1515    r"""
     
    574574            g = [lambda x: float(a) for a in g]
    575575            return g, None, None
    576576       
    577 def adapt_to_callable(f, nargs=None):
    578     """
    579     Tries to make every function in f into a (fast) callable
    580     function, returning a new list of functions and the expected
    581     arguments.
    582    
    583     INPUT:
    584    
    585     - ``f`` -- a list of functions; these can be symbolic expressions,
    586             polynomials, etc
    587            
    588     -  ``nargs`` -- number of input args to have in the output functions
    589    
    590     OUTPUT: functions, expected arguments
    591     """
    592     from sage.misc.misc import deprecation
    593     deprecation("adapt_to_callable is a deprecated function.  Please use functions from sage.misc.plot instead.")
    594    
    595     try:
    596         from sage.symbolic.callable import is_CallableSymbolicExpression
    597         if sum([is_CallableSymbolicExpression(z) for z in f]):
    598             # Sum to get common universe; this works since f is
    599             # callable, and summing gets the arguments in the right
    600             # order.
    601             vars = sum(f).args()
    602         else:
    603             # Otherwise any free variable names in any order
    604             try:
    605                 vars = tuple(sorted(set(sum( [z.variables() for z in f], ()) )))
    606                 if len(vars) > 1:
    607                     from sage.misc.misc import deprecation
    608                     deprecation("Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)")
    609             except AttributeError:
    610                 vars = ()
    611                 f = [fast_float_constant(x) for x in f]
    612     except TypeError:
    613         vars = ()
    614         f = [fast_float_constant(x) for x in f]
    615    
    616     if nargs is not None and len(vars) != nargs:
    617         vars = (vars + ('_',)*nargs)[:nargs]
    618        
    619     return fast_float(f, *vars), vars
  • sage/plot/plot3d/parametric_surface.pyx

    diff -r 338637719747 -r 33d569c5906f sage/plot/plot3d/parametric_surface.pyx
    a b  
    5656from sage.rings.all import RDF
    5757
    5858from base import RenderParams
    59 from sage.ext.fast_eval cimport FastDoubleFunc
     59#from sage.ext.fast_eval cimport FastDoubleFunc
    6060from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf
    61 from sage.ext.fast_eval import fast_float
     61#from sage.ext.fast_eval import fast_float
    6262
    6363
    6464cdef inline bint smash_edge(point_c* vs, face_c* f, int a, int b):
     
    175175        # We must triangulate before computing the bounding box; otherwise
    176176        # we'll get an empty bounding box, as the bounding box is computed
    177177        # using the triangulation, and before triangulating the triangulation
    178         # is empty. 
     178        # is empty.
    179179        self.triangulate()
    180180        return IndexFaceSet.bounding_box(self)
    181181       
     
    189189        to save memory, rather it is needed so normals of the triangles
    190190        can be calculated correctly.
    191191        """
     192        cdef double u, v
    192193        if render_params is None:
    193194            render_params = self.default_render_params()
    194195        ds = render_params.ds
     
    204205        cdef Py_ssize_t i, j
    205206        cdef Py_ssize_t n = len(urange) - 1
    206207        cdef Py_ssize_t m = len(vrange) - 1
    207         cdef double u, v
    208208        cdef Py_ssize_t ix = 0
    209209
    210210        _sig_on
     
    353353        elif PY_TYPE_CHECK(self.f, tuple):
    354354       
    355355                fx, fy, fz = self.f
    356                 fast_x = PY_TYPE_CHECK(fx, FastDoubleFunc) or PY_TYPE_CHECK(fx, Wrapper_rdf)
    357                 fast_y = PY_TYPE_CHECK(fy, FastDoubleFunc) or PY_TYPE_CHECK(fx, Wrapper_rdf)
    358                 fast_z = PY_TYPE_CHECK(fz, FastDoubleFunc) or PY_TYPE_CHECK(fx, Wrapper_rdf)
     356                fast_x = PY_TYPE_CHECK(fx, Wrapper_rdf)
     357                fast_y = PY_TYPE_CHECK(fy, Wrapper_rdf)
     358                fast_z = PY_TYPE_CHECK(fz, Wrapper_rdf)
    359359               
    360360                if fast_x or fast_y or fast_z:
    361                    
    362361                    m, n = len(urange), len(vrange)
    363362                    ulist = to_double_array(urange)
    364363                    vlist = to_double_array(vrange)
    365364               
    366                     if PY_TYPE_CHECK(fx, FastDoubleFunc):
    367                         for i from 0 <= i < m:
    368                             uv[0] = ulist[i]
    369                             for j from 0 <= j < n:
    370                                 uv[1] = vlist[j]
    371                                 self.vs[i*n+j].x = (<FastDoubleFunc>fx)._call_c(uv)
    372                     elif fast_x: # must be Wrapper_rdf
    373                         for i from 0 <= i < m:
    374                             uv[0] = ulist[i]
    375                             for j from 0 <= j < n:
    376                                 uv[1] = vlist[j]
    377                                 (<Wrapper_rdf>fx).call_c(uv, &self.vs[i*n+j].x)
     365                    for i from 0 <= i < m:
     366                        uv[0] = ulist[i]
     367                        for j from 0 <= j < n:
     368                            uv[1] = vlist[j]
     369                            (<Wrapper_rdf>fx).call_c(uv, &self.vs[i*n+j].x)
    378370                       
    379                                
    380                     if PY_TYPE_CHECK(fy, FastDoubleFunc):
    381                         for i from 0 <= i < m:
    382                             uv[0] = ulist[i]
    383                             for j from 0 <= j < n:
    384                                 uv[1] = vlist[j]
    385                                 self.vs[i*n+j].y = (<FastDoubleFunc>fy)._call_c(uv)
    386                     elif fast_y: # must be Wrapper_rdf
    387                         for i from 0 <= i < m:
    388                             uv[0] = ulist[i]
    389                             for j from 0 <= j < n:
    390                                 uv[1] = vlist[j]
    391                                 (<Wrapper_rdf>fy).call_c(uv, &self.vs[i*n+j].y)
    392371
    393                     if PY_TYPE_CHECK(fz, FastDoubleFunc):
    394                         for i from 0 <= i < m:
    395                             uv[0] = ulist[i]
    396                             for j from 0 <= j < n:
    397                                 uv[1] = vlist[j]
    398                                 self.vs[i*n+j].z = (<FastDoubleFunc>fz)._call_c(uv)
    399                     elif fast_z: # must be Wrapper_rdf
    400                         for i from 0 <= i < m:
    401                             uv[0] = ulist[i]
    402                             for j from 0 <= j < n:
    403                                 uv[1] = vlist[j]
    404                                 (<Wrapper_rdf>fz).call_c(uv, &self.vs[i*n+j].z)
     372                    for i from 0 <= i < m:
     373                        uv[0] = ulist[i]
     374                        for j from 0 <= j < n:
     375                            uv[1] = vlist[j]
     376                            (<Wrapper_rdf>fy).call_c(uv, &self.vs[i*n+j].y)
     377
     378                    for i from 0 <= i < m:
     379                        uv[0] = ulist[i]
     380                        for j from 0 <= j < n:
     381                            uv[1] = vlist[j]
     382                            (<Wrapper_rdf>fz).call_c(uv, &self.vs[i*n+j].z)
    405383
    406384                           
    407385                    sage_free(ulist)
  • sage/plot/plot3d/plot3d.py

    diff -r 338637719747 -r 33d569c5906f sage/plot/plot3d/plot3d.py
    a b  
    7878from sage.plot.colors import rainbow
    7979from texture import Texture, is_Texture
    8080
    81 from sage.ext.fast_eval import fast_float_arg, fast_float
     81from sage.ext.fast_callable import fast_callable_arg
    8282
    8383from sage.functions.trig import cos, sin
    8484
     
    582582    elif adaptive:
    583583        P = plot3d_adaptive(f, urange, vrange, **kwds)
    584584    else:
    585         u=fast_float_arg(0)
    586         v=fast_float_arg(1)
     585        u=fast_callable_arg(0,2,domain=float)
     586        v=fast_callable_arg(1,2,domain=float)
    587587        P=parametric_plot3d.parametric_plot3d((u,v,f), urange, vrange, **kwds)
    588588    P.frame_aspect_ratio([1.0,1.0,0.5])
    589589    return P
  • sage/rings/complex_double.pyx

    diff -r 338637719747 -r 33d569c5906f sage/rings/complex_double.pyx
    a b  
    829829        """
    830830        return complex(self._complex.dat[0], self._complex.dat[1])
    831831
     832    def _fast_callable_(self, etb):
     833        r"""
     834        Given an ExpressionTreeBuilder, return an Expression representing
     835        this value.
     836
     837        EXAMPLES::
     838
     839            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     840            sage: etb = ExpressionTreeBuilder(vars=[])
     841            sage: 23._fast_callable_(etb)
     842            add(mul(mul(add(mul(add(mul(add(mul(add(mul(v_0, -1), -12), v_0), 1/2), v_0), -1/95), v_0), -1/2), v_0), v_0), -4)
     843
     844        TESTS::
     845
     846            sage: R(2)._fast_callable_(etb)
     847            2
     848            sage: R(0)._fast_callable_(etb)
     849            0
     850            sage: fast_callable(R(2))(3)
     851            2
     852        """
     853        return etb.constant(self)
     854
     855
    832856    def _interface_init_(self, I=None):
    833857        """
    834858        Returns self formatted as a string, suitable as input to another
  • sage/rings/complex_number.pyx

    diff -r 338637719747 -r 33d569c5906f sage/rings/complex_number.pyx
    a b  
    971971                       mpfr_get_d(self.__im, rnd))
    972972        # return complex(float(self.__re), float(self.__im))
    973973
     974    def _fast_callable_(self, etb):
     975        r"""
     976        Given an ExpressionTreeBuilder, return an Expression representing
     977        this value.
     978
     979        EXAMPLES::
     980
     981            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     982            sage: etb = ExpressionTreeBuilder(vars=[])
     983            sage: 23._fast_callable_(etb)
     984            add(mul(mul(add(mul(add(mul(add(mul(add(mul(v_0, -1), -12), v_0), 1/2), v_0), -1/95), v_0), -1/2), v_0), v_0), -4)
     985
     986        TESTS::
     987
     988            sage: R(2)._fast_callable_(etb)
     989            2
     990            sage: R(0)._fast_callable_(etb)
     991            0
     992            sage: fast_callable(R(2))(3)
     993            2
     994        """
     995        return etb.constant(self)
     996
     997
    974998    def __richcmp__(left, right, int op):
    975999        return (<Element>left)._richcmp(right, op)
    9761000
  • sage/rings/integer.pyx

    diff -r 338637719747 -r 33d569c5906f sage/rings/integer.pyx
    a b  
    28522852            <type 'float'>
    28532853        """
    28542854        return mpz_get_d(self.value)
    2855    
     2855
     2856    def _fast_callable_(self, etb):
     2857        r"""
     2858        Given an ExpressionTreeBuilder, return an Expression representing
     2859        this value.
     2860
     2861        EXAMPLES::
     2862
     2863            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     2864            sage: etb = ExpressionTreeBuilder(vars=[])
     2865            sage: 23._fast_callable_(etb)
     2866            add(mul(mul(add(mul(add(mul(add(mul(add(mul(v_0, -1), -12), v_0), 1/2), v_0), -1/95), v_0), -1/2), v_0), v_0), -4)
     2867
     2868        TESTS::
     2869
     2870            sage: R(2)._fast_callable_(etb)
     2871            2
     2872            sage: R(0)._fast_callable_(etb)
     2873            0
     2874            sage: fast_callable(R(2))(3)
     2875            2
     2876        """
     2877        return etb.constant(self)
     2878
    28562879    def _rpy_(self):
    28572880        """
    28582881        Returns int(self) so that rpy can convert self into an object it
  • sage/rings/rational.pyx

    diff -r 338637719747 -r 33d569c5906f sage/rings/rational.pyx
    a b  
    18281828        """
    18291829        return mpq_get_d(self.value)
    18301830       
     1831    def _fast_callable_(self, etb):
     1832        r"""
     1833        Given an ExpressionTreeBuilder, return an Expression representing
     1834        this value.
     1835
     1836        EXAMPLES::
     1837
     1838            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     1839            sage: etb = ExpressionTreeBuilder(vars=[])
     1840            sage: 23._fast_callable_(etb)
     1841            add(mul(mul(add(mul(add(mul(add(mul(add(mul(v_0, -1), -12), v_0), 1/2), v_0), -1/95), v_0), -1/2), v_0), v_0), -4)
     1842
     1843        TESTS::
     1844
     1845            sage: R(2)._fast_callable_(etb)
     1846            2
     1847            sage: R(0)._fast_callable_(etb)
     1848            0
     1849            sage: fast_callable(R(2))(3)
     1850            2
     1851        """
     1852        return etb.constant(self)
     1853
     1854
    18311855    def __hash__(self):
    18321856        """
    18331857        Return hash of self.
  • sage/rings/real_double.pyx

    diff -r 338637719747 -r 33d569c5906f sage/rings/real_double.pyx
    a b  
    13041304        """
    13051305        return self._value
    13061306   
     1307    def _fast_callable_(self, etb):
     1308        r"""
     1309        Given an ExpressionTreeBuilder, return an Expression representing
     1310        this value.
     1311
     1312        EXAMPLES::
     1313
     1314            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     1315            sage: etb = ExpressionTreeBuilder(vars=[])
     1316            sage: 23._fast_callable_(etb)
     1317            add(mul(mul(add(mul(add(mul(add(mul(add(mul(v_0, -1), -12), v_0), 1/2), v_0), -1/95), v_0), -1/2), v_0), v_0), -4)
     1318
     1319        TESTS::
     1320
     1321            sage: R(2)._fast_callable_(etb)
     1322            2
     1323            sage: R(0)._fast_callable_(etb)
     1324            0
     1325            sage: fast_callable(R(2))(3)
     1326            2
     1327        """
     1328        return etb.constant(self)
     1329
     1330
    13071331    def _rpy_(self):
    13081332        """
    13091333        Returns self.__float__() for rpy to convert into the
  • sage/rings/real_mpfr.pyx

    diff -r 338637719747 -r 33d569c5906f sage/rings/real_mpfr.pyx
    a b  
    22112211    def __float__(self):
    22122212        return mpfr_get_d(self.value, (<RealField_class>self._parent).rnd)
    22132213
     2214    def _fast_callable_(self, etb):
     2215        r"""
     2216        Given an ExpressionTreeBuilder, return an Expression representing
     2217        this value.
     2218
     2219        EXAMPLES::
     2220
     2221            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     2222            sage: etb = ExpressionTreeBuilder(vars=[])
     2223            sage: 23._fast_callable_(etb)
     2224            add(mul(mul(add(mul(add(mul(add(mul(add(mul(v_0, -1), -12), v_0), 1/2), v_0), -1/95), v_0), -1/2), v_0), v_0), -4)
     2225
     2226        TESTS::
     2227
     2228            sage: R(2)._fast_callable_(etb)
     2229            2
     2230            sage: R(0)._fast_callable_(etb)
     2231            0
     2232            sage: fast_callable(R(2))(3)
     2233            2
     2234        """
     2235        return etb.constant(self)
     2236
     2237
    22142238    def _rpy_(self):
    22152239        """
    22162240        Returns self.__float__() for rpy to convert into the
  • sage/symbolic/expression.pyx

    diff -r 338637719747 -r 33d569c5906f sage/symbolic/expression.pyx
    a b  
    70467046        from sage.misc.functional import _do_show
    70477047        return _do_show(self)
    70487048
    7049     def plot(self, *args, **kwds):
     7049    def plot_unused(self, *args, **kwds):
    70507050        """
    70517051        Plot a symbolic expression. All arguments are passed onto the standard plot command.
    70527052       
     
    71627162            10201
    71637163            sage: plot(s)
    71647164        """
    7165         try:
     7165        #try:
    71667166            # First we try fast float.  However, this doesn't work on some
    71677167            # input where fast_callable works fine.
    7168             return self._fast_float_(*vars)
    7169         except (TypeError, NotImplementedError):
     7168            #return self._fast_float_(*vars)
     7169        #except (TypeError, NotImplementedError):
    71707170            # Now we try fast_callable as a fallback, since it works in some
    71717171            # cases when fast_float doesn't, e.g., when I is anywhere in the
    71727172            # expression fast_float doesn't work but fast_callable does in some
    71737173            # cases when the resulting expression is real.
    7174             from sage.ext.fast_callable import fast_callable
     7174        from sage.ext.fast_callable import fast_callable
    71757175            # I tried calling self._fast_callable_ but that's too complicated
    71767176            # of an interface so we just use the fast_callable function.
    7177             return fast_callable(self, vars=vars)
     7177        return fast_callable(self, vars=vars)
    71787178
    71797179    ############   
    71807180    # Calculus #
  • sage/symbolic/function.pyx

    diff -r 338637719747 -r 33d569c5906f sage/symbolic/function.pyx
    a b  
    4343cdef dict sfunction_serial_dict = {}
    4444
    4545from sage.misc.fpickle import pickle_function, unpickle_function
    46 from sage.ext.fast_eval import FastDoubleFunc
     46from sage.ext.fast_callable import Wrapper
     47#from sage.ext.fast_eval import FastDoubleFunc
    4748
    4849# List of functions which ginac allows us to define custom behavior for.
    4950# Changing the order of this list could cause problems unpickling old pickles.
     
    355356
    356357        # support fast_float
    357358        if self._nargs == 1:
    358             if isinstance(args[0], FastDoubleFunc):
     359            if isinstance(args[0], Wrapper):
    359360                try:
    360361                    return getattr(args[0], self._name)()
    361362                except AttributeError, err:
     
    569570            sage: erf(1.5)
    570571            0.966105146475311
    571572        """
    572         import sage.ext.fast_eval as fast_float
     573        from sage.ext.fast_callable import fast_callable_arg, fast_callable
    573574
    574         args = [fast_float.fast_float_arg(n) for n in range(self.number_of_arguments())]
     575        args = [fast_callable_arg(n,self.number_of_arguments) for n in range(self.number_of_arguments())]
    575576        try:
    576577            return self(*args)
    577578        except TypeError, err:
    578             return fast_float.fast_float_func(self, *args)
     579            return fast_callable(self, *args)
    579580
    580581    def _fast_callable_(self, etb):
    581582        r"""