Path: blob/develop/src/sage_setup/autogen/interpreters/internal/specs/rdf.py
4086 views
#*****************************************************************************1# Copyright (C) 2009 Carl Witty <[email protected]>2# Copyright (C) 2015 Jeroen Demeyer <[email protected]>3#4# This program is free software: you can redistribute it and/or modify5# it under the terms of the GNU General Public License as published by6# the Free Software Foundation, either version 2 of the License, or7# (at your option) any later version.8# http://www.gnu.org/licenses/9#*****************************************************************************1011from __future__ import print_function, absolute_import1213from .base import StackInterpreter14from ..instructions import (params_gen, instr_infix, instr_funcall_2args,15instr_unary, InstrSpec)16from ..memory import MemoryChunkConstants17from ..storage import ty_double, ty_python18from ..utils import reindent_lines as ri192021class RDFInterpreter(StackInterpreter):22r"""23A subclass of StackInterpreter, specifying an interpreter over24machine-floating-point values (C doubles). This is used for25both domain=RDF and domain=float; currently the only difference26between the two is the type of the value returned from the27wrapper (they use the same wrapper and interpreter).28"""2930name = 'rdf'3132def __init__(self):33r"""34Initialize an RDFInterpreter.3536EXAMPLES::3738sage: from sage_setup.autogen.interpreters.internal import *39sage: from sage_setup.autogen.interpreters.internal.specs.rdf import *40sage: interp = RDFInterpreter()41sage: interp.name42'rdf'43sage: interp.extra_class_members44'cdef object _domain\n'45sage: interp.extra_members_initialize46"self._domain = args['domain']\n"47sage: interp.adjust_retval48'self._domain'49sage: interp.mc_py_constants50{MC:py_constants}51sage: interp.chunks52[{MC:args}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}]53sage: interp.pg('A[D]', 'S')54([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])55sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])56sage: instrs['add']57add: SS->S = 'o0 = i0 + i1;'58sage: instrs['py_call']59py_call: *->S = '\nPyObject *py_arg...goto error;\n}\n'6061Make sure that pow behaves reasonably::6263sage: from sage.ext.fast_callable import ExpressionTreeBuilder64sage: etb = ExpressionTreeBuilder(vars=('x','y'))65sage: x = etb.var('x')66sage: y = etb.var('y')67sage: ff = fast_callable(x^y, domain=RDF)68sage: ff(1.5, 3)693.37570sage: ff(-2, 3)71-8.072sage: ff(-2, 1/3)73Traceback (most recent call last):74...75ValueError: negative number to a fractional power not real76"""7778super(RDFInterpreter, self).__init__(ty_double)79self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)80# This is a randomly chosen number. Whenever this number is81# returned, the wrapper has to check whether an exception actually82# happened, so if an expression evaluates to this number execution83# is slightly slower. Hopefully that won't happen too often :)84self.err_return = '-1094648009105371'85self.chunks = [self.mc_args, self.mc_constants, self.mc_py_constants,86self.mc_stack,87self.mc_code]88pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,89S=self.mc_stack, P=self.mc_py_constants)90self.pg = pg91self.c_header = '#include <gsl/gsl_math.h>'92self.pyx_header = 'cimport sage.libs.gsl.math # Add dependency on GSL'93instrs = [94InstrSpec('load_arg', pg('A[D]', 'S'),95code='o0 = i0;'),96InstrSpec('load_const', pg('C[D]', 'S'),97code='o0 = i0;'),98InstrSpec('return', pg('S', ''),99code='return i0;'),100InstrSpec('py_call', pg('P[D]S@D', 'S'),101uses_error_handler=True,102code=ri(0, """103PyObject *py_args = PyTuple_New(n_i1);104if (py_args == NULL) goto error;105int i;106for (i = 0; i < n_i1; i++) {107PyObject *arg = PyFloat_FromDouble(i1[i]);108if (arg == NULL) {109Py_DECREF(py_args);110goto error;111}112PyTuple_SET_ITEM(py_args, i, arg);113}114PyObject *result = PyObject_CallObject(i0, py_args);115Py_DECREF(py_args);116if (result == NULL) goto error;117/* If result is not a float, then this will turn it into a float first. */118o0 = PyFloat_AsDouble(result);119Py_DECREF(result);120if (o0 == -1 && PyErr_Occurred()) {121goto error;122}123""")),124InstrSpec('pow', pg('SS', 'S'),125uses_error_handler=True,126code=ri(0, """127/* See python's pow in floatobject.c */128if (i0 == 0) o0 = 1.0;129else {130if (i0 < 0 && i1 != floor(i1)) {131PyErr_SetString(PyExc_ValueError, "negative number to a fractional power not real");132goto error;133}134o0 = pow(i0, i1);135}136"""))137]138for (name, op) in [('add', '+'), ('sub', '-'),139('mul', '*'), ('div', '/')]:140instrs.append(instr_infix(name, pg('SS', 'S'), op))141instrs.append(instr_funcall_2args('ipow', pg('SD', 'S'), 'gsl_pow_int'))142for (name, op) in [('neg', '-i0'), ('invert', '1/i0'),143('abs', 'fabs(i0)')]:144instrs.append(instr_unary(name, pg('S', 'S'), op))145for name in ['sqrt', 'ceil', 'floor', 'sin', 'cos', 'tan',146'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',147'asinh', 'acosh', 'atanh', 'exp', 'log']:148instrs.append(instr_unary(name, pg('S', 'S'), "%s(i0)" % name))149self.instr_descs = instrs150self._set_opcodes()151# supported for exponents that fit in an int152self.ipow_range = (int(-2**31), int(2**31-1))153self.extra_class_members = "cdef object _domain\n"154self.extra_members_initialize = "self._domain = args['domain']\n"155self.adjust_retval = 'self._domain'156157158