Ticket #5572: improve_fast_callable.4.patch

File improve_fast_callable.4.patch, 75.1 KB (added by jason, 10 years ago)

apply instead of previous patches (now doctests in plot/*.py[x] pass)

  • module_list.py

    # HG changeset patch
    # User Jason Grout <jason-sage@creativetrax.com>
    # Date 1272108645 18000
    # Node ID d0d9385106b76fbf12912a11e93f22f32c886321
    # Parent  1451c00a8d44f78f01cb0dc22ebb7464cc6ad0e2
    [mq]: improve_fast_callable.patch
    
    diff -r 1451c00a8d44 -r d0d9385106b7 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 1451c00a8d44 -r d0d9385106b7 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 1451c00a8d44 -r d0d9385106b7 sage/ext/fast_callable.pyx
    a b  
    300300
    301301include "stdsage.pxi"
    302302
    303 def fast_callable(x, domain=None, vars=None,
    304                   _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=False,
    305                   expect_one_var=False):
     303def fast_callable(x, domain=None, vars=None, nvars=0):
    306304    r"""
    307305    Given an expression x, compiles it into a form that can be quickly
    308306    evaluated, given values for the variables in x.
     
    320318
    321319    If vars is None and x is a polynomial, then we will use the
    322320    generators of parent(x) as the variables; otherwise, vars must be
    323     specified (unless x is a symbolic expression with only one variable,
    324     and expect_one_var is True, in which case we will use that variable).
     321    specified.
    325322
    326323    EXAMPLES:
    327324        sage: var('x')
     
    383380        sage: fc = fast_callable(expr, domain=float)
    384381        sage: fc(5, 7)
    385382        0.55142668124169059
     383
     384    Fast callable functions
     385    -----------------------
     386   
     387    If variables names are passed in, then the function is called as if the variables were keyword arguments::
     388
     389        sage: a=fast_callable(lambda x,y: x**y, vars=['x','y'])
     390        sage: a(1,2)
     391        1
     392        sage: a(2,1)
     393        2
     394        sage: b=fast_callable(lambda x,y: x**y, vars=['y','x'])
     395        sage: b(1,2)
     396        2
     397        sage: b(2,1)
     398        1
     399   
     400    If no variable names are passed in, then the function argument list is the default value for the variables::
     401
     402        sage: c=fast_callable(lambda x,y: x**y)
     403        sage: c(1,2)
     404        1
     405        sage: c(2,1)
     406        2
     407
    386408    """
    387409    cdef Expression et
    388     if isinstance(x, Expression):
     410
     411    if isinstance(x, (tuple, list)):
     412        return tuple([fast_callable(xi, domain=domain, vars=vars, nvars=nvars) for xi in x])
     413
     414    import inspect
     415    from sage.symbolic.callable import is_CallableSymbolicExpression
     416    from sage.symbolic.expression import is_Expression
     417    from sage.rings.all import is_PolynomialRing, is_MPolynomialRing
     418    from sage.all import parent
     419
     420    if isinstance(x,Wrapper):
     421        return x # TODO: make it so that we can change the domain/variables.
     422    elif isinstance(x, Expression):
    389423        et = x
    390         vars = et._etb._vars
     424        if vars is None:
     425            vars = et._etb._vars
     426
     427    elif is_CallableSymbolicExpression(x):
     428        if vars is None:
     429            vars=x.arguments()
     430        vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(len(vars), nvars)]
     431        etb = ExpressionTreeBuilder(vars=vars, domain=domain)
     432        et = etb(x)
     433
     434    elif is_Expression(x):
     435        if nvars>0:
     436            if vars is None:
     437                currvars=0
     438                vars=[]
     439            else:
     440                currvars=len(vars)
     441            vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(currvars, nvars)]
     442        elif vars is None:
     443            raise ValueError, "List of variables must be specified for symbolic expressions"
     444           
     445               
     446        etb = ExpressionTreeBuilder(vars=vars, domain=domain)
     447        et = etb(x)
     448
     449    elif inspect.isfunction(x):
     450        f_args=inspect.getargspec(x)
     451        if f_args.defaults is None:
     452            args=f_args.args
     453        else:
     454            args=f_args.args[:-len(f_args.defaults)]
     455
     456        if vars is None:
     457            vars = args
     458
     459        vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(len(vars), nvars)]
     460        etb = ExpressionTreeBuilder(vars=vars, domain=domain)
     461        et = etb.call(x,*map(etb.var, args))
     462
     463    elif is_PolynomialRing(parent(x)) or is_MPolynomialRing(parent(x)):
     464        if vars is None:
     465            vars = parent(x).variable_names()
     466        vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(len(vars), nvars)]
     467        etb = ExpressionTreeBuilder(vars=vars, domain=domain)
     468        et = etb(x)
     469
    391470    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
     471        if nvars>0:
     472            if vars is None:
     473                currvars=0
     474                vars=[]
     475            else:
     476                currvars=len(vars)
     477            vars = list(vars) + ['EXTRA_VAR%d' % n for n in range(currvars, nvars)]
     478        etb = ExpressionTreeBuilder(vars=vars, domain=domain)
     479        et = etb(x)
    396480
    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())]
     481    builder, str = choose_domain(domain, len(vars) if vars is not None else 0)
     482    generate_code(et, str)
     483    str.instr('return')
     484    return builder(str.get_current())
    402485
    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()
    419         etb = ExpressionTreeBuilder(vars=vars, domain=domain)
    420         et = x._fast_callable_(etb)
     486
     487def choose_domain(domain, nvars):
     488    r"""
     489    TODO: Docs
     490    """
    421491    if isinstance(domain, RealField_class):
    422492        import sage.ext.interpreters.wrapper_rr
    423493        builder = sage.ext.interpreters.wrapper_rr.Wrapper_rr
    424 
    425494        str = InstructionStream(sage.ext.interpreters.wrapper_rr.metadata,
    426                                 len(vars),
     495                                nvars,
    427496                                domain)
    428497    elif domain == RDF or domain is float:
    429498        import sage.ext.interpreters.wrapper_rdf
    430499        builder = sage.ext.interpreters.wrapper_rdf.Wrapper_rdf
    431500        str = InstructionStream(sage.ext.interpreters.wrapper_rdf.metadata,
    432                                 len(vars),
     501                                nvars,
    433502                                domain)
    434503    elif domain == CDF:
    435504        import sage.ext.interpreters.wrapper_cdf
    436505        builder = sage.ext.interpreters.wrapper_cdf.Wrapper_cdf
    437506        str = InstructionStream(sage.ext.interpreters.wrapper_cdf.metadata,
    438                                 len(vars),
     507                                nvars,
    439508                                domain)
    440509    elif domain is None:
    441510        import sage.ext.interpreters.wrapper_py
    442511        builder = sage.ext.interpreters.wrapper_py.Wrapper_py
    443512        str = InstructionStream(sage.ext.interpreters.wrapper_py.metadata,
    444                                 len(vars))
     513                                nvars)
    445514    else:
    446515        import sage.ext.interpreters.wrapper_el
    447516        builder = sage.ext.interpreters.wrapper_el.Wrapper_el
    448517        str = InstructionStream(sage.ext.interpreters.wrapper_el.metadata,
    449                                 len(vars),
     518                                nvars,
    450519                                domain)
    451     generate_code(et, str)
    452     str.instr('return')
    453     return builder(str.get_current())
     520    return builder, str
    454521
    455522def function_name(fn):
    456523    r"""
     
    484551    except AttributeError:
    485552        return "{%r}" % fn
    486553
     554def fast_callable_arg(int n, nargs, domain):
     555    r"""
     556    Return a fast_callable function that merely returns a
     557    specific variable number out of nvars variables.
     558    """
     559    cdef Expression et
     560    etb = ExpressionTreeBuilder(vars=['v%d'%i for i in range(nargs)], domain=domain)
     561    et = etb.var('v%d'%n)
     562    builder, str = choose_domain(domain, nargs)
     563    generate_code(et, str)
     564    str.instr('return')
     565    return builder(str.get_current())
     566
     567
     568   
    487569cdef class ExpressionTreeBuilder:
    488570    r"""
    489571    A class with helper methods for building Expressions.
     
    527609            7.17897987691853e23
    528610        """
    529611
    530         if isinstance(vars, tuple):
     612        if vars is None:
     613            vars=[]
     614        elif isinstance(vars, tuple):
    531615            vars = list(vars)
    532616        elif not isinstance(vars, list):
    533617            vars = [vars]
     
    15511635    builtin_functions[func_all.abs_symbolic] = 'abs'
    15521636    return builtin_functions
    15531637
     1638
     1639
     1640
     1641
    15541642cpdef generate_code(Expression expr, stream):
    15551643    r"""
    15561644    Generate code from an Expression tree; write the result into an
  • deleted file sage/ext/fast_eval.pxd

    diff -r 1451c00a8d44 -r d0d9385106b7 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 1451c00a8d44 -r d0d9385106b7 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 1451c00a8d44 -r d0d9385106b7 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/complex_plot.pyx

    diff -r 1451c00a8d44 -r d0d9385106b7 sage/plot/complex_plot.pyx
    a b  
    306306    from sage.plot.misc import setup_for_eval_on_grid
    307307    from sage.ext.fast_callable import fast_callable
    308308    from sage.rings.complex_double import CDF
     309    from sage.symbolic.all import SR
     310    from sage.all import parent
    309311
     312    if parent(f) is SR:
     313        vars=f.variables()
     314        nvars=len(vars)
     315        if nvars==0:
     316            vars=['extra']
     317        elif nvars>1:
     318            raise ValueError, "fill function can have at most one variable"
     319    else:
     320        vars=None
    310321    try:
    311         f = fast_callable(f, domain=CDF, expect_one_var=True)
     322        f = fast_callable(f, vars=vars, domain=CDF)
    312323    except (AttributeError, TypeError, ValueError):
    313324        pass
    314325   
  • sage/plot/misc.py

    diff -r 1451c00a8d44 -r d0d9385106b7 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'):
     
    337337        sage: sage.plot.misc.setup_for_eval_on_grid([sin,cos], [(-1,1)], plot_points=9)
    338338        ((<sage.ext...>, <sage.ext...>), [(-1.0, 1.0, 0.25)])
    339339        sage: sage.plot.misc.setup_for_eval_on_grid([lambda x: x^2,cos], [(-1,1)], plot_points=9)
    340         ((<function <lambda> ...>, <sage.ext...>), [(-1.0, 1.0, 0.25)])
     340        ((<sage.ext...>, <sage.ext...>), [(-1.0, 1.0, 0.25)])
    341341        sage: sage.plot.misc.setup_for_eval_on_grid([x+y], [(x,-1,1),(y,-2,2)])
    342342        ((<sage.ext...>,), [(-1.0, 1.0, 2.0), (-2.0, 2.0, 4.0)])
    343343        sage: sage.plot.misc.setup_for_eval_on_grid(x+y, [(x,-1,1),(y,-1,1)], plot_points=[4,9])
     
    380380
    381381    # pad the variables if we don't have enough
    382382    nargs = len(ranges)
    383     if len(vars)<nargs:
    384         vars += ('_',)*(nargs-len(vars))
    385383
    386384    ranges = [[float(z) for z in r] for r in ranges]
    387385
     
    396394    plot_points = [int(p) if p>=2 else 2 for p in plot_points]
    397395    range_steps = [abs(range[1] - range[0])/(p-1) for range, p in zip(ranges, plot_points)]
    398396   
    399     options={}
    400     if nargs==1:
    401         options['expect_one_var']=True
    402 
    403397    if is_Vector(funcs):
    404398        funcs = list(funcs)
    405399
    406400    #TODO: raise an error if there is a function/method in funcs that takes more values than we have ranges
    407401
     402    if len(vars)==0:
     403        vars=None
     404       
    408405    if return_vars:
    409         return fast_float(funcs, *vars,**options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)], vars
     406        return fast_callable(funcs, vars=vars,nvars=nargs,domain=float), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)], vars
    410407    else:
    411         return fast_float(funcs, *vars,**options), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)]
     408        return fast_callable(funcs, vars=vars,nvars=nargs,domain=float), [tuple(range+[range_step]) for range,range_step in zip(ranges, range_steps)]
    412409       
    413410
    414411def unify_arguments(funcs):
  • sage/plot/plot.py

    diff -r 1451c00a8d44 -r d0d9385106b7 sage/plot/plot.py
    a b  
    181181
    182182    sage: y(x) = x*sin(x^2)
    183183    sage: v = [(x, y(x)) for x in [-3,-2.95,..,3]]
    184     sage: show(points(v, rgbcolor=(0.2,0.6, 0.1), pointsize=30) + plot(spline(v), -3.1, 3))
     184    sage: show(points(v, rgbcolor=(0.2,0.6, 0.1), pointsize=30) + line(spline(v)))
    185185
    186186Cycliclink::
    187187
     
    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
    368 
     367#from sage.ext.fast_eval import fast_float, fast_float_constant, is_fast_float
     368from sage.ext.fast_callable import fast_callable
    369369from sage.misc.html import html
    370370
    371371from misc import options, rename_keyword
     
    11241124       
    11251125        EXAMPLES::
    11261126       
    1127             sage: sum([plot(z*sin(x), 0, 10).plot3d(z) for z in range(6)]) #long
     1127            sage: sum([plot(z*sin(x), (x,0, 10)).plot3d(z) for z in range(6)]) #long
    11281128        """
    11291129        from sage.plot.plot3d.base import Graphics3dGroup
    11301130        g = Graphics3dGroup([g.plot3d(**kwds) for g in self.__objects])
     
    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)
     2639
     2640                from sage.symbolic.all import SR
     2641                from sage.all import parent
     2642                if parent(fill) is SR:
     2643                    fillvars=fill.variables()
     2644                    nfillvars=len(fillvars)
     2645                    if nfillvars==0:
     2646                        fillvars=['extravar']
     2647                    elif nfillvars>1:
     2648                        raise ValueError, "fill function can have at most one variable"
    26412649                else:
    2642                     fill_f = fill
     2650                    fillvars=None
     2651                fill_f = fast_callable(fill, vars=fillvars, domain=float)
    26432652
    26442653                filldata = generate_plot_points(fill_f, xrange, plot_points, adaptive_tolerance, \
    26452654                                                adaptive_recursion, randomize)
  • sage/plot/plot3d/parametric_plot3d.py

    diff -r 1451c00a8d44 -r d0d9385106b7 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 1451c00a8d44 -r d0d9385106b7 sage/plot/plot3d/parametric_surface.pyx
    a b  
    6363from sage.rings.all import RDF
    6464
    6565from base import RenderParams
    66 from sage.ext.fast_eval cimport FastDoubleFunc
     66#from sage.ext.fast_eval cimport FastDoubleFunc
    6767from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf
    68 from sage.ext.fast_eval import fast_float
     68#from sage.ext.fast_eval import fast_float
    6969
    7070
    7171cdef inline bint smash_edge(point_c* vs, face_c* f, int a, int b):
     
    314314        # We must triangulate before computing the bounding box; otherwise
    315315        # we'll get an empty bounding box, as the bounding box is computed
    316316        # using the triangulation, and before triangulating the triangulation
    317         # is empty. 
     317        # is empty.
    318318        self.triangulate()
    319319        return IndexFaceSet.bounding_box(self)
    320320       
     
    337337            sage: S = MobiusStrip(1,.2)                                             # indirect doctests
    338338            sage: S.show()                                                          # indirect doctests
    339339        """
     340        cdef double u, v
    340341        if render_params is None:
    341342            render_params = self.default_render_params()
    342343        ds = render_params.ds
     
    352353        cdef Py_ssize_t i, j
    353354        cdef Py_ssize_t n = len(urange) - 1
    354355        cdef Py_ssize_t m = len(vrange) - 1
    355         cdef double u, v
    356356        cdef Py_ssize_t ix = 0
    357357
    358358        _sig_on
     
    513513        elif PY_TYPE_CHECK(self.f, tuple):
    514514       
    515515                fx, fy, fz = self.f
    516                 fast_x = PY_TYPE_CHECK(fx, FastDoubleFunc) or PY_TYPE_CHECK(fx, Wrapper_rdf)
    517                 fast_y = PY_TYPE_CHECK(fy, FastDoubleFunc) or PY_TYPE_CHECK(fx, Wrapper_rdf)
    518                 fast_z = PY_TYPE_CHECK(fz, FastDoubleFunc) or PY_TYPE_CHECK(fx, Wrapper_rdf)
     516                fast_x = PY_TYPE_CHECK(fx, Wrapper_rdf)
     517                fast_y = PY_TYPE_CHECK(fy, Wrapper_rdf)
     518                fast_z = PY_TYPE_CHECK(fz, Wrapper_rdf)
    519519               
    520520                if fast_x or fast_y or fast_z:
    521                    
    522521                    m, n = len(urange), len(vrange)
    523522                    ulist = to_double_array(urange)
    524523                    vlist = to_double_array(vrange)
    525524               
    526                     if PY_TYPE_CHECK(fx, FastDoubleFunc):
    527                         for i from 0 <= i < m:
    528                             uv[0] = ulist[i]
    529                             for j from 0 <= j < n:
    530                                 uv[1] = vlist[j]
    531                                 self.vs[i*n+j].x = (<FastDoubleFunc>fx)._call_c(uv)
    532                     elif fast_x: # must be Wrapper_rdf
    533                         for i from 0 <= i < m:
    534                             uv[0] = ulist[i]
    535                             for j from 0 <= j < n:
    536                                 uv[1] = vlist[j]
    537                                 (<Wrapper_rdf>fx).call_c(uv, &self.vs[i*n+j].x)
     525                    for i from 0 <= i < m:
     526                        uv[0] = ulist[i]
     527                        for j from 0 <= j < n:
     528                            uv[1] = vlist[j]
     529                            (<Wrapper_rdf>fx).call_c(uv, &self.vs[i*n+j].x)
    538530                       
    539                                
    540                     if PY_TYPE_CHECK(fy, FastDoubleFunc):
    541                         for i from 0 <= i < m:
    542                             uv[0] = ulist[i]
    543                             for j from 0 <= j < n:
    544                                 uv[1] = vlist[j]
    545                                 self.vs[i*n+j].y = (<FastDoubleFunc>fy)._call_c(uv)
    546                     elif fast_y: # must be Wrapper_rdf
    547                         for i from 0 <= i < m:
    548                             uv[0] = ulist[i]
    549                             for j from 0 <= j < n:
    550                                 uv[1] = vlist[j]
    551                                 (<Wrapper_rdf>fy).call_c(uv, &self.vs[i*n+j].y)
    552531
    553                     if PY_TYPE_CHECK(fz, FastDoubleFunc):
    554                         for i from 0 <= i < m:
    555                             uv[0] = ulist[i]
    556                             for j from 0 <= j < n:
    557                                 uv[1] = vlist[j]
    558                                 self.vs[i*n+j].z = (<FastDoubleFunc>fz)._call_c(uv)
    559                     elif fast_z: # must be Wrapper_rdf
    560                         for i from 0 <= i < m:
    561                             uv[0] = ulist[i]
    562                             for j from 0 <= j < n:
    563                                 uv[1] = vlist[j]
    564                                 (<Wrapper_rdf>fz).call_c(uv, &self.vs[i*n+j].z)
     532                    for i from 0 <= i < m:
     533                        uv[0] = ulist[i]
     534                        for j from 0 <= j < n:
     535                            uv[1] = vlist[j]
     536                            (<Wrapper_rdf>fy).call_c(uv, &self.vs[i*n+j].y)
     537
     538                    for i from 0 <= i < m:
     539                        uv[0] = ulist[i]
     540                        for j from 0 <= j < n:
     541                            uv[1] = vlist[j]
     542                            (<Wrapper_rdf>fz).call_c(uv, &self.vs[i*n+j].z)
    565543
    566544                           
    567545                    sage_free(ulist)
  • sage/plot/plot3d/plot3d.py

    diff -r 1451c00a8d44 -r d0d9385106b7 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/symbolic/expression.pyx

    diff -r 1451c00a8d44 -r d0d9385106b7 sage/symbolic/expression.pyx
    a b  
    70617061        from sage.misc.functional import _do_show
    70627062        return _do_show(self)
    70637063
    7064     def plot(self, *args, **kwds):
     7064    def plot_unused(self, *args, **kwds):
    70657065        """
    70667066        Plot a symbolic expression. All arguments are passed onto the standard plot command.
    70677067       
     
    71777177            10201
    71787178            sage: plot(s)
    71797179        """
    7180         try:
     7180        #try:
    71817181            # First we try fast float.  However, this doesn't work on some
    71827182            # input where fast_callable works fine.
    7183             return self._fast_float_(*vars)
    7184         except (TypeError, NotImplementedError):
     7183            #return self._fast_float_(*vars)
     7184        #except (TypeError, NotImplementedError):
    71857185            # Now we try fast_callable as a fallback, since it works in some
    71867186            # cases when fast_float doesn't, e.g., when I is anywhere in the
    71877187            # expression fast_float doesn't work but fast_callable does in some
    71887188            # cases when the resulting expression is real.
    7189             from sage.ext.fast_callable import fast_callable
     7189        from sage.ext.fast_callable import fast_callable
    71907190            # I tried calling self._fast_callable_ but that's too complicated
    71917191            # of an interface so we just use the fast_callable function.
    7192             return fast_callable(self, vars=vars)
     7192        return fast_callable(self, vars=vars)
    71937193
    71947194    ############   
    71957195    # Calculus #
  • sage/symbolic/function.pyx

    diff -r 1451c00a8d44 -r d0d9385106b7 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:
     
    573574            sage: erf(1.5)
    574575            0.966105146475311
    575576        """
    576         import sage.ext.fast_eval as fast_float
     577        from sage.ext.fast_callable import fast_callable_arg, fast_callable
    577578
    578         args = [fast_float.fast_float_arg(n) for n in range(self.number_of_arguments())]
     579        args = [fast_callable_arg(n,self.number_of_arguments) for n in range(self.number_of_arguments())]
    579580        try:
    580581            return self(*args)
    581582        except TypeError, err:
    582             return fast_float.fast_float_func(self, *args)
     583            return fast_callable(self, *args)
    583584
    584585    def _fast_callable_(self, etb):
    585586        r"""