Path: blob/develop/src/sage_setup/autogen/interpreters/internal/specs/rdf.py
7485 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#*****************************************************************************101112from ..instructions import (13InstrSpec,14instr_funcall_2args,15instr_infix,16instr_unary,17params_gen,18)19from ..memory import MemoryChunkConstants20from ..storage import ty_double, ty_python21from ..utils import reindent_lines as ri22from .base import StackInterpreter232425class RDFInterpreter(StackInterpreter):26r"""27A subclass of StackInterpreter, specifying an interpreter over28machine-floating-point values (C doubles). This is used for29both domain=RDF and domain=float; currently the only difference30between the two is the type of the value returned from the31wrapper (they use the same wrapper and interpreter).32"""3334name = 'rdf'3536def __init__(self):37r"""38Initialize an RDFInterpreter.3940EXAMPLES::4142sage: from sage_setup.autogen.interpreters.internal import *43sage: from sage_setup.autogen.interpreters.internal.specs.rdf import *44sage: interp = RDFInterpreter()45sage: interp.name46'rdf'47sage: interp.extra_class_members48'cdef object _domain\n'49sage: interp.extra_members_initialize50"self._domain = args['domain']\n"51sage: interp.adjust_retval52'self._domain'53sage: interp.mc_py_constants54{MC:py_constants}55sage: interp.chunks56[{MC:args}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}]57sage: interp.pg('A[D]', 'S')58([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])59sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])60sage: instrs['add']61add: SS->S = 'o0 = i0 + i1;'62sage: instrs['py_call']63py_call: *->S = '\nPyObject *py_arg...goto error;\n}\n'6465Make sure that pow behaves reasonably::6667sage: from sage.ext.fast_callable import ExpressionTreeBuilder68sage: etb = ExpressionTreeBuilder(vars=('x','y'))69sage: x = etb.var('x')70sage: y = etb.var('y')71sage: ff = fast_callable(x^y, domain=RDF)72sage: ff(1.5, 3)733.37574sage: ff(-2, 3)75-8.076sage: ff(-2, 1/3)77Traceback (most recent call last):78...79ValueError: negative number to a fractional power not real80"""8182super().__init__(ty_double)83self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)84# This is a randomly chosen number. Whenever this number is85# returned, the wrapper has to check whether an exception actually86# happened, so if an expression evaluates to this number execution87# is slightly slower. Hopefully that won't happen too often :)88self.err_return = '-1094648009105371'89self.chunks = [self.mc_args, self.mc_constants, self.mc_py_constants,90self.mc_stack,91self.mc_code]92pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,93S=self.mc_stack, P=self.mc_py_constants)94self.pg = pg95self.c_header = '#include <gsl/gsl_math.h>'96self.pyx_header = 'cimport sage.libs.gsl.math # Add dependency on GSL'97instrs = [98InstrSpec('load_arg', pg('A[D]', 'S'),99code='o0 = i0;'),100InstrSpec('load_const', pg('C[D]', 'S'),101code='o0 = i0;'),102InstrSpec('return', pg('S', ''),103code='return i0;'),104InstrSpec('py_call', pg('P[D]S@D', 'S'),105uses_error_handler=True,106code=ri(0, """107PyObject *py_args = PyTuple_New(n_i1);108if (py_args == NULL) goto error;109int i;110for (i = 0; i < n_i1; i++) {111PyObject *arg = PyFloat_FromDouble(i1[i]);112if (arg == NULL) {113Py_DECREF(py_args);114goto error;115}116PyTuple_SET_ITEM(py_args, i, arg);117}118PyObject *result = PyObject_CallObject(i0, py_args);119Py_DECREF(py_args);120if (result == NULL) goto error;121/* If result is not a float, then this will turn it into a float first. */122o0 = PyFloat_AsDouble(result);123Py_DECREF(result);124if (o0 == -1 && PyErr_Occurred()) {125goto error;126}127""")),128InstrSpec('pow', pg('SS', 'S'),129uses_error_handler=True,130code=ri(0, """131/* See python's pow in floatobject.c */132if (i0 == 0) o0 = 1.0;133else {134if (i0 < 0 && i1 != floor(i1)) {135PyErr_SetString(PyExc_ValueError, "negative number to a fractional power not real");136goto error;137}138o0 = pow(i0, i1);139}140"""))141]142for (name, op) in [('add', '+'), ('sub', '-'),143('mul', '*'), ('div', '/')]:144instrs.append(instr_infix(name, pg('SS', 'S'), op))145instrs.append(instr_funcall_2args('ipow', pg('SD', 'S'), 'gsl_pow_int'))146for (name, op) in [('neg', '-i0'), ('invert', '1/i0'),147('abs', 'fabs(i0)')]:148instrs.append(instr_unary(name, pg('S', 'S'), op))149for name in ['sqrt', 'ceil', 'floor', 'sin', 'cos', 'tan',150'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',151'asinh', 'acosh', 'atanh', 'exp', 'log']:152instrs.append(instr_unary(name, pg('S', 'S'), "%s(i0)" % name))153self.instr_descs = instrs154self._set_opcodes()155# supported for exponents that fit in an int156self.ipow_range = (int(-2**31), int(2**31-1))157self.extra_class_members = "cdef object _domain\n"158self.extra_members_initialize = "self._domain = args['domain']\n"159self.adjust_retval = 'self._domain'160161162