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

File trac5093-fast-callable-cleanup.patch, 43.1 KB (added by cwitty, 14 years ago)
  • sage/calculus/calculus.py

    # HG changeset patch
    # User Carl Witty <cwitty@newtonlabs.com>
    # Date 1237396960 25200
    # Node ID a97f9d176f07425f7dc6c9965a931152469b7bdf
    # Parent  c8ebd6134a6ff8bde681161097f56c7892502ab8
    Fix bugs (and make minor enhancements) brought up by the reviewers/testers
    
    diff -r c8ebd6134a6f -r a97f9d176f07 sage/calculus/calculus.py
    a b  
    56245624            add(v_0, v_1)
    56255625            sage: (-x)._fast_callable_(etb)
    56265626            neg(v_0)
    5627         """
    5628         fops = [op._fast_callable_(etb) for op in self._operands]
    5629         return self._operator(*fops)
     5627
     5628        TESTS::
     5629
     5630            sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)
     5631            sage: (x^7)._fast_callable_(etb)
     5632            ipow(v_0, 7)
     5633        """
     5634        # This used to convert the operands first.  Doing it this way
     5635        # instead gives a chance to notice powers with an integer
     5636        # exponent before the exponent gets (potentially) converted
     5637        # to another type.
     5638        return etb.call(self._operator, *self._operands)
    56305639
    56315640    def _convert(self, typ):
    56325641        """
     
    62326241            sage: z._fast_callable_(etb)
    62336242            Traceback (most recent call last):
    62346243            ...
    6235             ValueError: list.index(x): x not in list
     6244            ValueError: Variable 'z' not found
    62366245        """
    62376246        return etb.var(self)
    62386247
  • sage/ext/fast_callable.pyx

    diff -r c8ebd6134a6f -r a97f9d176f07 sage/ext/fast_callable.pyx
    a b  
    3232sage: wilk = prod((x-i) for i in [1 .. 20]); wilk
    3333(x - 20)*(x - 19)*(x - 18)*(x - 17)*(x - 16)*(x - 15)*(x - 14)*(x - 13)*(x - 12)*(x - 11)*(x - 10)*(x - 9)*(x - 8)*(x - 7)*(x - 6)*(x - 5)*(x - 4)*(x - 3)*(x - 2)*(x - 1)
    3434sage: timeit('wilk.subs(x=30)') # random, long time
    35 625 loops, best of 3: 1.46 ms per loop
     35625 loops, best of 3: 1.43 ms per loop
    3636sage: fc_wilk = fast_callable(wilk)
    3737sage: timeit('fc_wilk(30)') # random, long time
    38 625 loops, best of 3: 10.4 us per loop
     38625 loops, best of 3: 9.72 us per loop
    3939
    4040You can specify a particular domain for the evaluation using
    4141\code{domain=}:
     
    5959how that compares to the generic fc_wilk example above:
    6060
    6161sage: timeit('fc_wilk_zz(30)') # random, long time
    62 625 loops, best of 3: 15.6 us per loop
     62625 loops, best of 3: 15.4 us per loop
    6363
    6464However, for other types, using domain=D will get a large speedup,
    6565because we have special-purpose interpreters for those types.  One
     
    7070
    7171sage: fc_wilk_rdf = fast_callable(wilk, domain=RDF)
    7272sage: timeit('fc_wilk_rdf(30.0)') # random, long time
    73 625 loops, best of 3: 5.13 us per loop
     73625 loops, best of 3: 7 us per loop
     74
     75The domain does not need to be a Sage type; for instance, domain=float
     76also works.  (We actually use the same fast interpreter for domain=float
     77and domain=RDF; the only difference is that when domain=RDF is used,
     78the return value is an RDF element, and when domain=float is used,
     79the return value is a Python float.)
     80
     81sage: fc_wilk_float = fast_callable(wilk, domain=float)
     82sage: timeit('fc_wilk_float(30.0)') # random, long time
     83625 loops, best of 3: 5.04 us per loop
    7484
    7585We also have support for RR:
    7686
    7787sage: fc_wilk_rr = fast_callable(wilk, domain=RR)
    7888sage: timeit('fc_wilk_rr(30.0)') # random, long time
    79 625 loops, best of 3: 12.9 us per loop
     89625 loops, best of 3: 13 us per loop
    8090
    8191By default, \function{fast_callable} uses the same variable names in the
    8292same order that the \method{__call__} method on its argument would use;
     
    165175EXAMPLES:
    166176    sage: var('x')
    167177    x
    168     sage: f = fast_callable(sqrt(x^7+1), domain=RDF)
     178    sage: f = fast_callable(sqrt(x^7+1), domain=float)
    169179
    170180    sage: f(1)
    171181    1.4142135623730951
    172182    sage: f.op_list()
    173     [('load_arg', 0), ('load_const', 7.0), 'pow', ('load_const', 1.0), 'add', 'sqrt', 'return']
     183    [('load_arg', 0), ('ipow', 7), ('load_const', 1.0), 'add', 'sqrt', 'return']
    174184   
    175185    To interpret that last line, we load argument 0 ('x' in this case) onto
    176186    the stack, push the constant 7.0 onto the stack, call the pow function
     
    185195    sage: f = etb.call(sqrt, x^7 + 1)
    186196    sage: g = etb.call(sin, x)
    187197    sage: fast_callable(f+g).op_list()
    188     [('load_arg', 0), ('load_const', 7), 'pow', ('load_const', 1), 'add', ('py_call', sqrt, 1), ('load_arg', 0), ('py_call', sin, 1), 'add', 'return']
     198    [('load_arg', 0), ('ipow', 7), ('load_const', 1), 'add', ('py_call', sqrt, 1), ('load_arg', 0), ('py_call', sin, 1), 'add', 'return']
    189199
    190200
    191201AUTHOR:
     
    265275from sage.structure.element cimport Element
    266276from sage.rings.all import RDF
    267277from sage.libs.mpfr cimport mpfr_t, mpfr_ptr, mpfr_init2, mpfr_set, GMP_RNDN
     278from sage.rings.integer import Integer
     279from sage.rings.integer_ring import ZZ
    268280
    269281include "stdsage.pxi"
    270282
     
    277289    method and a ._fast_callable_() method (this includes SR, univariate
    278290    polynomials, and multivariate polynomials).
    279291
    280     By default, x is evaluated the same way that a Python function would
    281     evaluate it -- addition maps to PyNumber_Add, etc.  However, you
    282     can specify domain=D where D is some Sage parent; in this case,
    283     all arithmetic is done in that parent.  If we have a special-purpose
    284     interpreter for that parent (like RDF), domain=RDF will trigger the
    285     use of that interpreter.
     292    By default, x is evaluated the same way that a Python function
     293    would evaluate it -- addition maps to PyNumber_Add, etc.  However,
     294    you can specify domain=D where D is some Sage parent or Python
     295    type; in this case, all arithmetic is done in that domain.  If we
     296    have a special-purpose interpreter for that parent (like RDF or float),
     297    domain=... will trigger the use of that interpreter.
    286298
    287299    If vars is None, then we will attempt to determine the set of
    288300    variables from x; otherwise, we will use the given set.
     
    296308        sin(2) + 12
    297309        sage: f(2.0)
    298310        12.9092974268257
     311
     312    We have special fast interpreters for domain=float and domain=RDF.
     313    (Actually it's the same interpreter; only the return type varies.)
     314    Note that the float interpreter is not actually more accurate than
     315    the RDF interpreter; elements of RDF just don't display all
     316    their digits.
     317
     318        sage: f_float = fast_callable(expr, domain=float)
     319        sage: f_float(2)
     320        12.909297426825681
    299321        sage: f_rdf = fast_callable(expr, domain=RDF)
    300322        sage: f_rdf(2)
    301         12.909297426825681
     323        12.9092974268
    302324        sage: f = fast_callable(expr, vars=('z','x','y'))
    303325        sage: f(1, 2, 3)
    304326        sin(2) + 12
     
    309331        sage: fp.op_list()
    310332        [('load_arg', 0), ('load_const', -1.0), 'mul', ('load_const', -12.0), 'add', ('load_arg', 0), 'mul', ('load_const', 0.5), 'add', ('load_arg', 0), 'mul', ('load_const', -0.0105263157895), 'add', ('load_arg', 0), 'mul', ('load_const', -0.5), 'add', ('load_arg', 0), 'mul', ('load_arg', 0), 'mul', ('load_const', -4.0), 'add', 'return']
    311333        sage: fp(3.14159)
    312         -4594.1618236401764
     334        -4594.16182364
    313335        sage: K.<x,y,z> = QQ[]
    314336        sage: p = K.random_element(degree=3, terms=5); p
    315337        -x*y^2 - x*z^2 - 6*x^2 - y^2 - 3*x*z
    316338        sage: fp = fast_callable(p, domain=RDF)
    317339        sage: fp.op_list()
    318         [('load_const', 0.0), ('load_const', -3.0), ('load_arg', 0), ('load_const', 1.0), 'pow', ('load_arg', 2), ('load_const', 1.0), 'pow', 'mul', 'mul', 'add', ('load_const', -1.0), ('load_arg', 0), ('load_const', 1.0), 'pow', ('load_arg', 1), ('load_const', 2.0), 'pow', 'mul', 'mul', 'add', ('load_const', -6.0), ('load_arg', 0), ('load_const', 2.0), 'pow', 'mul', 'add', ('load_const', -1.0), ('load_arg', 1), ('load_const', 2.0), 'pow', 'mul', 'add', ('load_const', -1.0), ('load_arg', 0), ('load_const', 1.0), 'pow', ('load_arg', 2), ('load_const', 2.0), 'pow', 'mul', 'mul', 'add', 'return']
     340        [('load_const', 0.0), ('load_const', -3.0), ('load_arg', 0), ('ipow', 1), ('load_arg', 2), ('ipow', 1), 'mul', 'mul', 'add', ('load_const', -1.0), ('load_arg', 0), ('ipow', 1), ('load_arg', 1), ('ipow', 2), 'mul', 'mul', 'add', ('load_const', -6.0), ('load_arg', 0), ('ipow', 2), 'mul', 'add', ('load_const', -1.0), ('load_arg', 1), ('ipow', 2), 'mul', 'add', ('load_const', -1.0), ('load_arg', 0), ('ipow', 1), ('load_arg', 2), ('ipow', 2), 'mul', 'mul', 'add', 'return']
    319341        sage: fp(e, pi, sqrt(2))
    320         -98.001564033629322
     342        -98.0015640336
    321343        sage: symbolic_result = p(e, pi, sqrt(2)); symbolic_result
    322344        -1*e*pi^2 - pi^2 - 6*e^2 - 3*sqrt(2)*e - 2*e
    323345        sage: n(symbolic_result)
    324346        -98.0015640336293
    325347
    326348        sage: from sage.ext.fast_callable import ExpressionTreeBuilder
    327         sage: etb = ExpressionTreeBuilder(vars=('x','y'), domain=RDF)
     349        sage: etb = ExpressionTreeBuilder(vars=('x','y'), domain=float)
    328350        sage: x = etb.var('x')
    329351        sage: y = etb.var('y')
    330352        sage: expr = etb.call(sin, x^2 + y); expr
    331         sin(add(pow(v_0, 2.0), v_1))
    332         sage: fc = fast_callable(expr, domain=RDF)
     353        sin(add(ipow(v_0, 2), v_1))
     354        sage: fc = fast_callable(expr, domain=float)
    333355        sage: fc(5, 7)
    334356        0.55142668124169059
    335357    """
     
    357379        str = InstructionStream(sage.ext.interpreters.wrapper_rr.metadata,
    358380                                len(vars),
    359381                                domain)
    360     elif domain == RDF:
     382    elif domain == RDF or domain is float:
    361383        import sage.ext.interpreters.wrapper_rdf
    362384        builder = sage.ext.interpreters.wrapper_rdf.Wrapper_rdf
    363385        str = InstructionStream(sage.ext.interpreters.wrapper_rdf.metadata,
    364                                 len(vars))
     386                                len(vars),
     387                                domain)
    365388    elif domain is None:
    366389        import sage.ext.interpreters.wrapper_py
    367390        builder = sage.ext.interpreters.wrapper_py.Wrapper_py
     
    550573            sage: etb.var('y')
    551574            Traceback (most recent call last):
    552575            ...
    553             ValueError: list.index(x): x not in list           
     576            ValueError: Variable 'y' not found
    554577        """
    555         ind = self._vars.index(self._clean_var(v))
     578        var_name = self._clean_var(v)
     579        try:
     580            ind = self._vars.index(var_name)
     581        except ValueError:
     582            raise ValueError, "Variable '%s' not found" % var_name
    556583        return ExpressionVariable(self, ind)
    557584
    558585    def _var_number(self, n):
     
    581608        The arguments will be converted to Expressions using
    582609        ExpressionTreeBuilder.__call__.
    583610
     611        As a special case, notices if the function is operator.pow and
     612        the second argument is integral, and constructs an ExpressionIPow
     613        instead.
     614
    584615        EXAMPLES:
    585616            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
    586617            sage: etb = ExpressionTreeBuilder(vars=(x,))
     
    592623            sin(1)
    593624            sage: etb.call(factorial, x+57)
    594625            {factorial}(add(v_0, 57))
     626            sage: etb.call(operator.pow, x, 543)
     627            ipow(v_0, 543)
    595628        """
    596         return ExpressionCall(self, fn, map(self, args))
     629        if fn is operator.pow:
     630            base, exponent = args
     631            return self(base)**exponent
     632        else:
     633            return ExpressionCall(self, fn, map(self, args))
    597634
    598635    def choice(self, cond, iftrue, iffalse):
    599636        r"""
     
    791828        r"""
    792829        Compute a power expression from two Expressions.
    793830
     831        If the second Expression is a constant integer, then return
     832        an ExpressionIPow instead of an ExpressionCall.
     833
    794834        EXAMPLES:
    795835            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
    796836            sage: etb = ExpressionTreeBuilder(vars=(x,))
     
    798838            sage: x^x
    799839            pow(v_0, v_0)
    800840            sage: x^1
    801             pow(v_0, 1)
     841            ipow(v_0, 1)
    802842            sage: x.__pow__(1)
    803             pow(v_0, 1)
     843            ipow(v_0, 1)
     844            sage: x.__pow__(1.0)
     845            pow(v_0, 1.00000000000000)
    804846            sage: x.__rpow__(1)
    805847            pow(1, v_0)
    806848        """
     
    811853        # (Plus, we should consider how strict a semantics we want;
    812854        # probably this sort of optimization should be controlled by a
    813855        # flag.)
    814         return _expression_binop_helper(s, o, op_pow)
     856       
     857        cdef Expression es
     858        if isinstance(o, (int, long, Integer)):
     859            es = s
     860            return ExpressionIPow(es._etb, s, o)
     861        else:
     862            # I really don't like this, but I can't think of a better way
     863            from sage.calculus.calculus import is_SymbolicExpression
     864            if is_SymbolicExpression(o) and o in ZZ:
     865                es = s
     866                return ExpressionIPow(es._etb, s, ZZ(o))
     867            else:
     868                return _expression_binop_helper(s, o, op_pow)
    815869       
    816870    def __neg__(self):
    817871        r"""
     
    10881142        fn = function_name(self._function)
    10891143        return '%s(%s)' % (fn, ', '.join(map(repr, self._arguments)))
    10901144
     1145cdef class ExpressionIPow(Expression):
     1146    r"""
     1147    A power Expression with an integer exponent.
     1148
     1149    EXAMPLES:
     1150        sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     1151        sage: etb = ExpressionTreeBuilder(vars=(x,))
     1152        sage: type(etb.var('x')^17)
     1153        <type 'sage.ext.fast_callable.ExpressionIPow'>
     1154    """
     1155    cdef object _base
     1156    cdef object _exponent
     1157
     1158    def __init__(self, etb, base, exponent):
     1159        r"""
     1160        Initialize an ExpressionIPow.
     1161
     1162        EXAMPLES:
     1163            sage: from sage.ext.fast_callable import ExpressionTreeBuilder, ExpressionIPow
     1164            sage: etb = ExpressionTreeBuilder(vars=(x,))
     1165            sage: x = etb(x)
     1166            sage: x^(-12)
     1167            ipow(v_0, -12)
     1168            sage: v = ExpressionIPow(etb, x, 55); v
     1169            ipow(v_0, 55)
     1170            sage: v._get_etb() is etb
     1171            True
     1172            sage: v.base()
     1173            v_0
     1174            sage: v.exponent()
     1175            55
     1176        """
     1177        Expression.__init__(self, etb)
     1178        self._base = base
     1179        self._exponent = exponent
     1180
     1181    def base(self):
     1182        r"""
     1183        Return the base from this ExpressionIPow.
     1184
     1185        EXAMPLES:
     1186            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     1187            sage: etb = ExpressionTreeBuilder(vars=(x,))
     1188            sage: (etb(33)^42).base()
     1189            33
     1190        """
     1191        return self._base
     1192
     1193    def exponent(self):
     1194        r"""
     1195        Return the exponent from this ExpressionIPow.
     1196
     1197        EXAMPLES:
     1198            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     1199            sage: etb = ExpressionTreeBuilder(vars=(x,))
     1200            sage: (etb(x)^(-1)).exponent()
     1201            -1
     1202        """
     1203        return self._exponent
     1204
     1205    def __repr__(self):
     1206        r"""
     1207        Give a string representing this ExpressionIPow.
     1208
     1209        EXAMPLES:
     1210            sage: from sage.ext.fast_callable import ExpressionTreeBuilder
     1211            sage: etb = ExpressionTreeBuilder(vars=(x,))
     1212            sage: x = etb.var(x)
     1213            sage: x^3
     1214            ipow(v_0, 3)
     1215            sage: x^(-2)
     1216            ipow(v_0, -2)
     1217            sage: v = (x+1)^3
     1218            sage: v
     1219            ipow(add(v_0, 1), 3)
     1220            sage: repr(v)
     1221            'ipow(add(v_0, 1), 3)'
     1222            sage: v.__repr__()
     1223            'ipow(add(v_0, 1), 3)'
     1224        """
     1225        return 'ipow(%s, %d)' % (repr(self._base), self._exponent)
     1226
    10911227cdef class ExpressionChoice(Expression):
    10921228    r"""
    10931229    A conditional expression.
     
    12391375
    12401376   return ExpressionCall(self._etb, op, [self, other])
    12411377
     1378class IntegerPowerFunction(object):
     1379    r"""
     1380    This class represents the function x^n for an arbitrary integral
     1381    power n.  That is, IntegerPowerFunction(2) is the squaring function;
     1382    IntegerPowerFunction(-1) is the reciprocal function.
     1383
     1384    EXAMPLES:
     1385        sage: from sage.ext.fast_callable import IntegerPowerFunction
     1386        sage: square = IntegerPowerFunction(2)
     1387        sage: square
     1388        (^2)
     1389        sage: square(pi)
     1390        pi^2
     1391        sage: square(I)
     1392        -1
     1393        sage: square(RIF(-1, 1)).str(style='brackets')
     1394        '[0.00000000000000000 .. 1.0000000000000000]'
     1395        sage: IntegerPowerFunction(-1)
     1396        (^(-1))
     1397        sage: IntegerPowerFunction(-1)(22/7)
     1398        7/22
     1399        sage: v = Integers(123456789)(54321)
     1400        sage: v^9876543210
     1401        79745229
     1402        sage: IntegerPowerFunction(9876543210)(v)   
     1403        79745229
     1404    """
     1405
     1406    def __init__(self, n):
     1407        r"""
     1408        Initializes an IntegerPowerFunction.
     1409
     1410        EXAMPLES:
     1411            sage: from sage.ext.fast_callable import IntegerPowerFunction
     1412            sage: cube = IntegerPowerFunction(3)
     1413            sage: cube
     1414            (^3)
     1415            sage: cube(AA(7)^(1/3))
     1416            7.000000000000000?
     1417            sage: cube.exponent
     1418            3
     1419        """
     1420        self.exponent = n
     1421
     1422    def __repr__(self):
     1423        r"""
     1424        Return a string representing this IntegerPowerFunction.
     1425
     1426        EXAMPLES:
     1427            sage: from sage.ext.fast_callable import IntegerPowerFunction
     1428            sage: square = IntegerPowerFunction(2)
     1429            sage: square
     1430            (^2)
     1431            sage: repr(square)
     1432            '(^2)'
     1433            sage: square.__repr__()
     1434            '(^2)'
     1435            sage: repr(IntegerPowerFunction(-57))
     1436            '(^(-57))'
     1437        """
     1438        if self.exponent >= 0:
     1439            return "(^%s)" % self.exponent
     1440        else:
     1441            return "(^(%s))" % self.exponent
     1442
     1443    def __call__(self, x):
     1444        r"""
     1445        Call this IntegerPowerFunction, to compute a power of its argument.
     1446
     1447        EXAMPLES:
     1448            sage: from sage.ext.fast_callable import IntegerPowerFunction
     1449            sage: square = IntegerPowerFunction(2)
     1450            sage: square.__call__(5)
     1451            25
     1452            sage: square(5)
     1453            25
     1454        """
     1455        return x**self.exponent
     1456
    12421457builtin_functions = None
    12431458cpdef get_builtin_functions():
    12441459    r"""
     
    13241539        8.2831853071795864769252867665590057684
    13251540        sage: fc = fast_callable(expr, domain=RDF)
    13261541        sage: fc(0)
    1327         3.1415926535897931
     1542        3.14159265359
    13281543        sage: fc(1)
    1329         8.2831853071795862
     1544        8.28318530718
    13301545        sage: fc.op_list()
    13311546        [('load_arg', 0), ('load_const', pi), 'add', ('load_arg', 0), ('load_const', 1), 'add', 'mul', 'return']
    13321547        sage: fc = fast_callable(etb.call(sin, x) + etb.call(sqrt, x), domain=RDF)
    13331548        sage: fc(1)
    1334         1.8414709848078965
     1549        1.84147098481
    13351550        sage: fc.op_list()
    13361551        [('load_arg', 0), 'sin', ('load_arg', 0), 'sqrt', 'add', 'return']
    13371552        sage: fc = fast_callable(etb.call(sin, x) + etb.call(sqrt, x))
     
    13411556        [('load_arg', 0), ('py_call', sin, 1), ('load_arg', 0), ('py_call', sqrt, 1), 'add', 'return']
    13421557        sage: fc = fast_callable(etb.call(my_sin, x), domain=RDF)
    13431558        sage: fc(3)
    1344         0.14112000805986721
     1559        0.14112000806
    13451560        sage: fc = fast_callable(etb.call(my_sin, x), domain=RealField(100))
    13461561        sage: fc(3)
    13471562        0.14112000805986722210074480281
     
    13491564        [('load_arg', 0), ('py_call', <function my_sin at 0x...>, 1), 'return']
    13501565        sage: fc = fast_callable(etb.call(my_sqrt, x), domain=RDF)
    13511566        sage: fc(3)
    1352         1.7320508075688772
     1567        1.73205080757
     1568        sage: parent(fc(3))
     1569        Real Double Field
    13531570        sage: fc(-3)
    13541571        Traceback (most recent call last):
    13551572        ...
     
    13991616        Traceback (most recent call last):
    14001617        ...
    14011618        TypeError: unable to convert x (=sin(3)) to an integer
     1619
     1620        sage: fc = fast_callable(etb(x)^100)
     1621        sage: fc(pi)
     1622        pi^100
     1623        sage: fc = fast_callable(etb(x)^100, domain=ZZ)
     1624        sage: fc(2)
     1625        1267650600228229401496703205376
     1626        sage: fc = fast_callable(etb(x)^100, domain=RIF)
     1627        sage: fc(RIF(-2))
     1628        1.2676506002282295?e30
     1629        sage: fc = fast_callable(etb(x)^100, domain=RDF)
     1630        sage: fc.op_list()
     1631        [('load_arg', 0), ('ipow', 100), 'return']
     1632        sage: fc(1.1)
     1633        13780.6123398
     1634        sage: fc = fast_callable(etb(x)^100, domain=RR)
     1635        sage: fc.op_list()
     1636        [('load_arg', 0), ('ipow', 100), 'return']
     1637        sage: fc(1.1)
     1638        13780.6123398224
     1639        sage: fc = fast_callable(etb(x)^(-100), domain=RDF)
     1640        sage: fc.op_list()
     1641        [('load_arg', 0), ('ipow', -100), 'return']
     1642        sage: fc(1.1)
     1643        7.25657159015e-05
     1644        sage: fc = fast_callable(etb(x)^(-100), domain=RR)
     1645        sage: fc(1.1)
     1646        0.0000725657159014814
     1647        sage: expo = 2^32
     1648        sage: base = (1.0).nextabove()
     1649        sage: fc = fast_callable(etb(x)^expo, domain=RDF)
     1650        sage: fc.op_list()
     1651        [('load_arg', 0), ('py_call', (^4294967296), 1), 'return']
     1652        sage: fc(base)
     1653        1.00000095367
     1654        sage: RDF(base)^expo
     1655        1.00000095367
     1656        sage: fc = fast_callable(etb(x)^expo, domain=RR)
     1657        sage: fc.op_list()
     1658        [('load_arg', 0), ('py_call', (^4294967296), 1), 'return']
     1659        sage: fc(base)
     1660        1.00000095367477
     1661        sage: base^expo
     1662        1.00000095367477
    14021663    """
    14031664    cdef ExpressionConstant econst
    14041665    cdef ExpressionVariable evar
     
    14261687            stream.instr('py_call', fn, len(ecall._arguments))
    14271688        else:
    14281689            raise ValueError, "Unhandled function %s in generate_code" % fn
     1690    elif isinstance(expr, ExpressionIPow):
     1691        base = expr.base()
     1692        exponent = expr.exponent()
     1693        metadata = stream.get_metadata()
     1694        ipow_range = metadata.ipow_range
     1695        if ipow_range is True:
     1696            use_ipow = True
     1697        elif isinstance(ipow_range, tuple):
     1698            a,b = ipow_range
     1699            use_ipow = (a <= exponent <= b)
     1700        else:
     1701            use_ipow = False
     1702        generate_code(base, stream)
     1703        if use_ipow:
     1704            stream.instr('ipow', exponent)
     1705        else:
     1706            stream.instr('py_call', IntegerPowerFunction(exponent), 1)
    14291707    else:
    14301708        raise ValueError, "Unhandled expression kind %s in generate_code" % type(expr)
    14311709
     
    16041882                    self._bytecode.append(loc)
    16051883            elif spec.parameters[i] == 'args':
    16061884                self._bytecode.append(args[i])
     1885            elif spec.parameters[i] == 'code':
     1886                self._bytecode.append(args[i])
    16071887            elif spec.parameters[i] == 'n_inputs':
    16081888                self._bytecode.append(args[i])
    16091889                n_inputs = args[i]
     
    16311911        Returns the interpreter metadata being used by the current
    16321912        InstructionStream.
    16331913
    1634         (Probably only useful for writing doctests.)
     1914        The code generator sometimes uses this to decide which code
     1915        to generate.
    16351916
    16361917        EXAMPLES:
    16371918            sage: from sage.ext.interpreters.wrapper_rdf import metadata
     
    16841965            sage: instr_stream.current_op_list()
    16851966            [('load_arg', 0), ('py_call', <built-in function sin>, 1), 'abs', 'return']
    16861967            sage: instr_stream.get_current()
    1687             {'domain': None, 'code': [0, 0, 3, 0, 1, 11, 2], 'py_constants': [<built-in function sin>], 'args': 1, 'stack': 1, 'constants': []}
     1968            {'domain': None, 'code': [0, 0, 3, 0, 1, 12, 2], 'py_constants': [<built-in function sin>], 'args': 1, 'stack': 1, 'constants': []}
    16881969        """
    16891970        d = {'args': self._n_args,
    16901971             'constants': self._constants,
     
    16971978class InterpreterMetadata(object):
    16981979    r"""
    16991980    The interpreter metadata for a fast_callable interpreter.  Currently
    1700     only consists of a dictionary mapping instruction names to
    1701     (CompilerInstrSpec, opcode) pairs, and a list mapping opcodes to
    1702     (instruction name, CompilerInstrSpec) pairs.
     1981    consists of a dictionary mapping instruction names to
     1982    (CompilerInstrSpec, opcode) pairs, a list mapping opcodes to
     1983    (instruction name, CompilerInstrSpec) pairs, and a range of exponents
     1984    for which the ipow instruction can be used.  This range can be
     1985    False (if the ipow instruction should never be used), a pair of
     1986    two integers (a,b), if ipow should be used for a<=n<=b, or True,
     1987    if ipow should always be used.  When ipow cannot be used, then
     1988    we fall back on calling IntegerPowerFunction.
    17031989
    17041990    See the class docstring for CompilerInstrSpec for more information.
    17051991
    17061992    NOTE: You must not modify the metadata.
    17071993    """
    17081994
    1709     def __init__(self, by_opname, by_opcode):
     1995    def __init__(self, by_opname, by_opcode, ipow_range):
    17101996        r"""
    17111997        Initialize an InterpreterMetadata object.
    17121998
     
    17152001
    17162002        Currently we do no error checking or processing, so we can
    17172003        use this simple test:
    1718             sage: metadata = InterpreterMetadata(by_opname='opname dict goes here', by_opcode='opcode list goes here')
     2004            sage: metadata = InterpreterMetadata(by_opname='opname dict goes here', by_opcode='opcode list goes here', ipow_range=(2, 57))
    17192005            sage: metadata.by_opname
    17202006            'opname dict goes here'
    17212007            sage: metadata.by_opcode
    17222008            'opcode list goes here'
     2009            sage: metadata.ipow_range
     2010            (2, 57)
    17232011        """
    17242012        self.by_opname = by_opname
    17252013        self.by_opcode = by_opcode
     2014        self.ipow_range = ipow_range
    17262015
    17272016class CompilerInstrSpec(object):
    17282017    r"""
     
    18172106            for p in instr.parameters:
    18182107                p_loc = code[0]
    18192108                code = code[1:]
    1820                 if p in ('args', 'n_inputs', 'n_outputs'):
     2109                if p in ('args', 'code', 'n_inputs', 'n_outputs'):
    18212110                    op.append(p_loc)
    18222111                else:
    18232112                    op.append(args[p][p_loc])
     
    18692158
    18702159        EXAMPLES:
    18712160            sage: fast_callable(sin(x)/x, domain=RDF).get_orig_args()
    1872             {'domain': None, 'code': [0, 0, 15, 0, 0, 7, 2], 'py_constants': [], 'args': 1, 'stack': 2, 'constants': []}
     2161            {'domain': Real Double Field, 'code': [0, 0, 16, 0, 0, 7, 2], 'py_constants': [], 'args': 1, 'stack': 2, 'constants': []}
    18732162        """
    18742163        return self._orig_args
    18752164
  • sage/ext/fast_eval.pyx

    diff -r c8ebd6134a6f -r a97f9d176f07 sage/ext/fast_eval.pyx
    a b  
    8888#*****************************************************************************
    8989
    9090from sage.ext.fast_callable import fast_callable, Wrapper
    91 from sage.rings.all import RDF
    9291
    9392include "stdsage.pxi"
    9493
     
    13481347        if old:
    13491348            return f._fast_float_(*vars)
    13501349        else:
    1351             return fast_callable(f, vars=vars, domain=RDF)
     1350            return fast_callable(f, vars=vars, domain=float)
    13521351    except AttributeError:
    13531352        pass
    13541353
  • sage/ext/gen_interpreters.py

    diff -r c8ebd6134a6f -r a97f9d176f07 sage/ext/gen_interpreters.py
    a b  
    104104from distutils.extension import Extension
    105105
    106106##############################
    107 # This module is used during the Sage buld process, so it should not
     107# This module is used during the Sage build process, so it should not
    108108# use any other Sage modules.  (In particular, it MUST NOT use any
    109109# Cython modules -- they won't be built yet!)
    110110# Also, we have some trivial dependency tracking, where we don't
    111111# rebuild the interpreters if this file hasn't changed; if
    112 # interpreter configuation is split out into a separate file,
     112# interpreter configuration is split out into a separate file,
    113113# that will have to be changed.
    114114##############################
    115115
     
    16441644            chunk = chunks[chunk_code]
    16451645            addr = None
    16461646            ch_len = None
    1647             if chunk.is_stack():
     1647            # shouldn't hardcode 'code' here
     1648            if chunk.is_stack() or chunk.name == 'code':
    16481649                pass
    16491650            else:
    16501651                m = re.match(r'\[(?:([0-9]+)|([a-zA-Z]))\]', s)
     
    19591960        err_return -- a string indicating the value to be returned
    19601961                      in case of a Python exception
    19611962        mc_code -- a memory chunk to use for the interpreted code
     1963        extra_class_members -- Class members for the wrapper that
     1964                               don't correspond to memory chunks
     1965        extra_members_initialize -- Code to initialize extra_class_members
    19621966                     
    19631967        EXAMPLES:
    19641968            sage: from sage.ext.gen_interpreters import *
    19651969            sage: interp = RDFInterpreter()
    19661970            sage: interp.header
    1967             ''
     1971            '\n#include <gsl/gsl_math.h>\n'
    19681972            sage: interp.pyx_header
    19691973            ''
    19701974            sage: interp.err_return
    19711975            '-1094648009105371'
    19721976            sage: interp.mc_code
    19731977            {MC:code}
     1978            sage: interp = RRInterpreter()
     1979            sage: interp.extra_class_members
     1980            ''
     1981            sage: interp.extra_members_initialize
     1982            ''
    19741983        """
    19751984        self.header = ''
    19761985        self.pyx_header = ''
    19771986        self.err_return = 'NULL'
    19781987        self.mc_code = MemoryChunkConstants('code', ty_int)
     1988        self.extra_class_members = ''
     1989        self.extra_members_initialize = ''
    19791990
    19801991    def _set_opcodes(self):
    19811992        r"""
     
    20172028        return_type -- the type returned by the C interpreter (None for int,
    20182029                       where 1 means success and 0 means error)
    20192030        mc_retval -- None, or the MemoryChunk to use as a return value
     2031        ipow_range -- the range of exponents supported by the ipow
     2032                      instruction (default is False, meaning never use ipow)
     2033        adjust_retval -- None, or a string naming a function to call
     2034                         in the wrapper's __call__ to modify the return
     2035                         value of the interpreter
    20202036
    20212037        EXAMPLES:
    20222038            sage: from sage.ext.gen_interpreters import *
     
    20442060        else:
    20452061            self.return_type = None
    20462062        self.mc_retval = mc_retval
     2063        self.ipow_range = False
     2064        self.adjust_retval = None
    20472065
    20482066class RDFInterpreter(StackInterpreter):
    20492067    r"""
    20502068    A subclass of StackInterpreter, specifying an interpreter over
    2051     machine-floating-point values (C doubles).
     2069    machine-floating-point values (C doubles).  This is used for
     2070    both domain=RDF and domain=float; currently the only difference
     2071    between the two is the type of the value returned from the
     2072    wrapper (they use the same wrapper and interpreter).
    20522073    """
    20532074
    20542075    def __init__(self):
     
    20602081            sage: interp = RDFInterpreter()
    20612082            sage: interp.name
    20622083            'rdf'
     2084            sage: interp.extra_class_members
     2085            'cdef object _domain\n'
     2086            sage: interp.extra_members_initialize
     2087            "self._domain = args['domain']\n"
     2088            sage: interp.adjust_retval
     2089            'self._domain'
    20632090            sage: interp.mc_py_constants
    20642091            {MC:py_constants}
    20652092            sage: interp.chunks
     
    20872114        pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
    20882115                        S=self.mc_stack, P=self.mc_py_constants)
    20892116        self.pg = pg
     2117        self.header = """
     2118#include <gsl/gsl_math.h>
     2119"""
    20902120        instrs = [
    20912121            InstrSpec('load_arg', pg('A[D]', 'S'),
    20922122                       code='o0 = i0;'),
     
    21232153                           ('mul', '*'), ('div', '/')]:
    21242154            instrs.append(instr_infix(name, pg('SS', 'S'), op))
    21252155        instrs.append(instr_funcall_2args('pow', pg('SS', 'S'), 'pow'))
     2156        instrs.append(instr_funcall_2args('ipow', pg('SD', 'S'), 'gsl_pow_int'))
    21262157        for (name, op) in [('neg', '-i0'), ('invert', '1/i0'),
    21272158                           ('abs', 'fabs(i0)')]:
    21282159            instrs.append(instr_unary(name, pg('S', 'S'), op))
     
    21322163            instrs.append(instr_unary(name, pg('S',  'S'), "%s(i0)" % name))
    21332164        self.instr_descs = instrs
    21342165        self._set_opcodes()
     2166        # supported for exponents that fit in an int
     2167        self.ipow_range = (int(-2**31), int(2**31-1))
     2168        self.extra_class_members = "cdef object _domain\n"
     2169        self.extra_members_initialize = "self._domain = args['domain']\n"
     2170        self.adjust_retval = 'self._domain'
    21352171       
    21362172class RRInterpreter(StackInterpreter):
    21372173    r"""
     
    22552291                           ('mul', 'mpfr_mul'), ('div', 'mpfr_div'),
    22562292                           ('pow', 'mpfr_pow')]:
    22572293            instrs.append(instr_funcall_2args_mpfr(name, pg('SS', 'S'), op))
     2294        instrs.append(instr_funcall_2args_mpfr('ipow', pg('SD', 'S'), 'mpfr_pow_si'))
    22582295        for name in ['neg', 'abs',
    22592296                     'log', 'log2', 'log10',
    22602297                     'exp', 'exp2', 'exp10',
     
    22772314                                 code='mpfr_ui_div(o0, 1, i0, GMP_RNDN);'))
    22782315        self.instr_descs = instrs
    22792316        self._set_opcodes()
     2317        # Supported for exponents that fit in a long, so we could use
     2318        # a much wider range on a 64-bit machine.  On the other hand,
     2319        # it's easier to write the code this way, and constant integer
     2320        # exponents outside this range probably aren't very common anyway.
     2321        self.ipow_range = (int(-2**31), int(2**31-1))
    22802322
    22812323class PythonInterpreter(StackInterpreter):
    22822324    r"""
     
    23002342    it's different than Py_XDECREF followed by assigning NULL.)
    23012343
    23022344    Note that as a tiny optimization, the interpreter always assumes
    2303     (and assures) that empty parts of the stack contain NULL, so
     2345    (and ensures) that empty parts of the stack contain NULL, so
    23042346    it doesn't bother to Py_XDECREF before it pushes onto the stack.
    23052347    """
    23062348
     
    23682410            instrs.append(instr_funcall_2args(name, pg('SS', 'S'), op))
    23692411        instrs.append(InstrSpec('pow', pg('SS', 'S'),
    23702412                                code='o0 = PyNumber_Power(i0, i1, Py_None);'))
     2413        instrs.append(InstrSpec('ipow', pg('SC[D]', 'S'),
     2414                                code='o0 = PyNumber_Power(i0, i1, Py_None);'))
    23712415        for (name, op) in [('neg', 'PyNumber_Negative'),
    23722416                           ('invert', 'PyNumber_Invert'),
    23732417                           ('abs', 'PyNumber_Absolute')]:
    23742418            instrs.append(instr_unary(name, pg('S', 'S'), '%s(i0)'%op))
    23752419        self.instr_descs = instrs
    23762420        self._set_opcodes()
     2421        # Always use ipow
     2422        self.ipow_range = True
    23772423       
    23782424class ElementInterpreter(PythonInterpreter):
    23792425    r"""
     
    25422588            if input_len is not None:
    25432589                w("        int n_i%d = %s;\n" % (i, string_of_addr(input_len)))
    25442590            if not ch.is_stack():
    2545                 if input_len is not None:
     2591                # Shouldn't hardcode 'code' here
     2592                if ch.name == 'code':
     2593                    w("        %s i%d = %s;\n" % (chst.c_local_type(), i, string_of_addr(ch)))
     2594                elif input_len is not None:
    25462595                    w("        %s i%d = %s + ai%d;\n" %
    25472596                      (chst.c_ptr_type(), i, ch.name, i))
    25482597                else:
     
    27422791
    27432792        the_call = je("""
    27442793        {% if s.return_type %}return {% endif -%}
     2794{% if s.adjust_retval %}{{ s.adjust_retval }}({% endif %}
    27452795interp_{{ s.name }}({{ arg_ch.pass_argument() }}
    27462796{% for ch in s.chunks[1:] %}
    27472797            , {{ ch.pass_argument() }}
    27482798{% endfor %}
    2749             )
     2799            ){% if s.adjust_retval %}){% endif %}
     2800
    27502801""", s=s, arg_ch=arg_ch)
    27512802
    27522803        w(je("""
     
    27832834{% for ch in s.chunks %}
    27842835{% print ch.declare_class_members() %}
    27852836{% endfor %}
     2837{% print indent_lines(4, s.extra_class_members) %}
    27862838
    27872839    def __init__(self, args):
    27882840        Wrapper.__init__(self, args, metadata)
     
    27952847{% for ch in s.chunks %}
    27962848{% print ch.init_class_members() %}
    27972849{% endfor %}
     2850{% print indent_lines(8, s.extra_members_initialize) %}
    27982851
    27992852    def __dealloc__(self):
    28002853        cdef int i
     
    28402893  ('{{ instr.name }}',
    28412894   CompilerInstrSpec({{ instr.n_inputs }}, {{ instr.n_outputs }}, {{ instr.parameters }})),
    28422895{% endfor %}
    2843  ])
     2896 ],
     2897 ipow_range={{ s.ipow_range }})
    28442898""", s=s, self=self, types=types, arg_ch=arg_ch, indent_lines=indent_lines, the_call=the_call, do_cleanup=do_cleanup))
    28452899
    28462900    def get_interpreter(self):
     
    28952949        simplest instructions:
    28962950            sage: print rdf_interp
    28972951            /* ... */ ...
    2898                 case 9: /* neg */
     2952                case 10: /* neg */
    28992953                  {
    29002954                    double i0 = *--stack;
    29012955                    double o0;
     
    29132967        type.
    29142968            sage: print rr_interp
    29152969            /* ... */ ...
    2916                 case 9: /* neg */
     2970                case 10: /* neg */
    29172971                  {
    29182972                    mpfr_ptr i0 = *--stack;
    29192973                    mpfr_ptr o0 = *stack++;
     
    29322986        Python-object element interpreter.
    29332987            sage: print el_interp
    29342988            /* ... */ ...
    2935                 case 9: /* neg */
     2989                case 10: /* neg */
    29362990                  {
    29372991                    PyObject* i0 = *--stack;
    29382992                    *stack = NULL;
     
    31533207        Finally we get to the __call__ method.  We grab the arguments
    31543208        passed by the caller, stuff them in our pre-allocated
    31553209        argument array, and then call the C interpreter.
     3210
     3211        We optionally adjust the return value of the interpreter
     3212        (currently only the RDF/float interpreter performs this step;
     3213        this is the only place where domain=RDF differs than
     3214        domain=float):
     3215
    31563216            sage: print rdf_wrapper
    31573217            # ...
    31583218                def __call__(self, *args):
     
    31613221                    cdef int i
    31623222                    for i from 0 <= i < len(args):
    31633223                        self._args[i] = args[i]
    3164                     return interp_rdf(c_args
     3224                    return self._domain(interp_rdf(c_args
    31653225                        , self._constants
    31663226                        , self._py_constants
    31673227                        , self._stack
    31683228                        , self._code
    3169                         )
     3229                        ))
    31703230            ...
    31713231
    31723232        In Python-object based interpreters, the call to the C
     
    32003260        documented at InterpreterMetadata; for now, we'll just show
    32013261        what it looks like.
    32023262
    3203         Currently, there are two parts to the metadata; the first maps
     3263        Currently, there are three parts to the metadata; the first maps
    32043264        instruction names to instruction descriptions.  The second one
    32053265        maps opcodes to instruction descriptions.  Note that we don't
    32063266        use InstrSpec objects here; instead, we use CompilerInstrSpec
    32073267        objects, which are much simpler and contain only the information
    3208         we'll need at runtime.
     3268        we'll need at runtime.  The third part says what range the
     3269        ipow instruction is defined over.
    32093270
    32103271        First the part that maps instruction names to
    32113272        (CompilerInstrSpec, opcode) pairs.
     
    32373298              ('add',
    32383299               CompilerInstrSpec(2, 1, [])),
    32393300            ...
    3240              ])
     3301             ], ...)
     3302
     3303        And then the ipow range:
     3304            sage: print rdf_wrapper
     3305            # ...
     3306            metadata = InterpreterMetadata(..., 
     3307              ipow_range=(-2147483648, 2147483647))
     3308           
    32413309
    32423310        And that's it for the wrapper.           
    32433311        """
     
    33673435modules = [
    33683436    Extension('sage.ext.interpreters.wrapper_rdf',
    33693437              sources = ['sage/ext/interpreters/wrapper_rdf.pyx',
    3370                          'sage/ext/interpreters/interp_rdf.c']),
     3438                         'sage/ext/interpreters/interp_rdf.c'],
     3439              libraries = ['gsl']),
    33713440
    33723441    Extension('sage.ext.interpreters.wrapper_rr',
    33733442              sources = ['sage/ext/interpreters/wrapper_rr.pyx',
  • sage/numerical/optimize.py

    diff -r c8ebd6134a6f -r a97f9d176f07 sage/numerical/optimize.py
    a b  
    235235    if isinstance(func,SymbolicExpression):
    236236        var_list=func.variables()
    237237        var_names=map(str,var_list)
    238         fast_f=fast_callable(func, vars=var_names, domain=RDF)
     238        fast_f=fast_callable(func, vars=var_names, domain=float)
    239239        f=lambda p: fast_f(*p)
    240240        gradient_list=func.gradient()
    241         fast_gradient_functions=[fast_callable(gradient_list[i], vars=var_names, domain=RDF)  for i in xrange(len(gradient_list))]
     241        fast_gradient_functions=[fast_callable(gradient_list[i], vars=var_names, domain=float)  for i in xrange(len(gradient_list))]
    242242        gradient=lambda p: scipy.array([ a(*p) for a in fast_gradient_functions])       
    243243    else:
    244244        f=func
     
    260260        elif algorithm=="ncg":
    261261            if isinstance(func,SymbolicExpression):
    262262                hess=func.hessian()
    263                 hess_fast= [ [fast_callable(a, vars=var_names, domain=RDF) for a in row] for row in hess]
     263                hess_fast= [ [fast_callable(a, vars=var_names, domain=float) for a in row] for row in hess]
    264264                hessian=lambda p: [[a(*p) for a in row] for row in hess_fast]
    265265                hessian_p=lambda p,v: scipy.dot(scipy.array(hessian(p)),v)
    266266                min= optimize.fmin_ncg(f,map(float,x0),fprime=gradient,fhess=hessian,fhess_p=hessian_p,**args)
  • sage/rings/polynomial/multi_polynomial.pyx

    diff -r c8ebd6134a6f -r a97f9d176f07 sage/rings/polynomial/multi_polynomial.pyx
    a b  
    260260            sage: v = K.random_element(degree=3, terms=4); v
    261261            -6/5*x*y*z + 2*y*z^2 - x
    262262            sage: v._fast_callable_(etb)
    263             add(add(add(0, mul(-6/5, mul(mul(pow(v_0, 1), pow(v_1, 1)), pow(v_2, 1)))), mul(2, mul(pow(v_1, 1), pow(v_2, 2)))), mul(-1, pow(v_0, 1)))
     263            add(add(add(0, mul(-6/5, mul(mul(ipow(v_0, 1), ipow(v_1, 1)), ipow(v_2, 1)))), mul(2, mul(ipow(v_1, 1), ipow(v_2, 2)))), mul(-1, ipow(v_0, 1)))
    264264       
    265265        TESTS:
     266            sage: v = K(0)
     267            sage: vf = fast_callable(v)
     268            sage: type(v(0r, 0r, 0r))
     269            <type 'sage.rings.rational.Rational'>
     270            sage: type(vf(0r, 0r, 0r))
     271            <type 'sage.rings.rational.Rational'>
    266272            sage: K.<x,y,z> = QQ[]
    267273            sage: from sage.ext.fast_eval import fast_float
    268274            sage: fast_float(K(0)).op_list()
     
    270276            sage: fast_float(K(17)).op_list()
    271277            [('load_const', 0.0), ('load_const', 17.0), 'add', 'return']
    272278            sage: fast_float(y).op_list()
    273             [('load_const', 0.0), ('load_const', 1.0), ('load_arg', 1), ('load_const', 1.0), 'pow', 'mul', 'add', 'return']
     279            [('load_const', 0.0), ('load_const', 1.0), ('load_arg', 1), ('ipow', 1), 'mul', 'add', 'return']
    274280        """
    275281        my_vars = self.parent().variable_names()
    276282        x = [etb.var(v) for v in my_vars]
    277283        n = len(x)
    278284
    279         expr = etb.constant(0)
     285        expr = etb.constant(self.base_ring()(0))
    280286        for (m, c) in self.dict().iteritems():
    281287            monom = misc.mul([ x[i]**m[i] for i in range(n) if m[i] != 0],
    282288                             etb.constant(c))