Path: blob/develop/src/sage_setup/autogen/interpreters/internal/specs/cdf.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_complex, ty_python18from ..utils import reindent_lines as ri192021class CDFInterpreter(StackInterpreter):22r"""23A subclass of StackInterpreter, specifying an interpreter over24complex machine-floating-point values (C doubles).25"""2627name = 'cdf'2829def __init__(self):30r"""31Initialize a CDFInterpreter.3233EXAMPLES::3435sage: from sage_setup.autogen.interpreters.internal import *36sage: from sage_setup.autogen.interpreters.internal.specs.cdf import *37sage: interp = CDFInterpreter()38sage: interp.name39'cdf'40sage: interp.mc_py_constants41{MC:py_constants}42sage: interp.chunks43[{MC:args}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}]44sage: interp.pg('A[D]', 'S')45([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])46sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])47sage: instrs['add']48add: SS->S = 'o0 = i0 + i1;'49sage: instrs['sin']50sin: S->S = 'o0 = csin(i0);'51sage: instrs['py_call']52py_call: *->S = '\nif (!cdf_py_call_...goto error;\n}\n'5354A test of integer powers::5556sage: f(x) = sum(x^k for k in [-20..20])57sage: f(CDF(1+2j)) # rel tol 4e-1658-10391778.999999996 + 3349659.499999962*I59sage: ff = fast_callable(f, CDF)60sage: ff(1 + 2j) # rel tol 1e-1461-10391779.000000004 + 3349659.49999997*I62sage: ff.python_calls()63[]6465sage: f(x) = sum(x^k for k in [0..5])66sage: ff = fast_callable(f, CDF)67sage: ff(2)6863.069sage: ff(2j)7013.0 + 26.0*I71"""7273super(CDFInterpreter, self).__init__(ty_double_complex)74self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)75# See comment for RDFInterpreter76self.err_return = '-1094648119105371'77self.adjust_retval = "dz_to_CDE"78self.chunks = [self.mc_args, self.mc_constants, self.mc_py_constants,79self.mc_stack,80self.mc_code]81pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,82S=self.mc_stack, P=self.mc_py_constants)83self.pg = pg84self.c_header = ri(0,"""85#include <stdlib.h>86#include <complex.h>8788/* On Solaris, we need to define _Imaginary_I when compiling with GCC,89* otherwise the constant I doesn't work. The definition below is based90* on glibc. */91#ifdef __GNUC__92#undef _Imaginary_I93#define _Imaginary_I (__extension__ 1.0iF)94#endif9596typedef double complex double_complex;9798static inline double complex csquareX(double complex z) {99double complex res;100__real__(res) = __real__(z) * __real__(z) - __imag__(z) * __imag__(z);101__imag__(res) = 2 * __real__(z) * __imag__(z);102return res;103}104105static inline double complex cpow_int(double complex z, int exp) {106if (exp < 0) return 1/cpow_int(z, -exp);107switch (exp) {108case 0: return 1;109case 1: return z;110case 2: return csquareX(z);111case 3: return csquareX(z) * z;112case 4:113case 5:114case 6:115case 7:116case 8:117{118double complex z2 = csquareX(z);119double complex z4 = csquareX(z2);120if (exp == 4) return z4;121if (exp == 5) return z4 * z;122if (exp == 6) return z4 * z2;123if (exp == 7) return z4 * z2 * z;124if (exp == 8) return z4 * z4;125}126}127if (cimag(z) == 0) return pow(creal(z), exp);128if (creal(z) == 0) {129double r = pow(cimag(z), exp);130switch (exp % 4) {131case 0:132return r;133case 1:134return r * I;135case 2:136return -r;137default /* case 3 */:138return -r * I;139}140}141return cpow(z, exp);142}143""")144145self.pxd_header = ri(0, """146# This is to work around a header incompatibility with PARI using147# "I" as variable conflicting with the complex "I".148# If we cimport pari earlier, we avoid this problem.149cimport cypari2.types150151# We need the type double_complex to work around152# http://trac.cython.org/ticket/869153# so this is a bit hackish.154cdef extern from "complex.h":155ctypedef double double_complex "double complex"156""")157158self.pyx_header = ri(0, """159from sage.libs.gsl.complex cimport *160from sage.rings.complex_double cimport ComplexDoubleElement161import sage.rings.complex_double162cdef object CDF = sage.rings.complex_double.CDF163164cdef extern from "complex.h":165cdef double creal(double_complex)166cdef double cimag(double_complex)167cdef double_complex _Complex_I168169cdef inline double_complex CDE_to_dz(zz) noexcept:170cdef ComplexDoubleElement z = <ComplexDoubleElement>(zz if isinstance(zz, ComplexDoubleElement) else CDF(zz))171return GSL_REAL(z._complex) + _Complex_I * GSL_IMAG(z._complex)172173cdef inline ComplexDoubleElement dz_to_CDE(double_complex dz):174cdef ComplexDoubleElement z = <ComplexDoubleElement>ComplexDoubleElement.__new__(ComplexDoubleElement)175GSL_SET_COMPLEX(&z._complex, creal(dz), cimag(dz))176return z177178cdef public bint cdf_py_call_helper(object fn,179int n_args,180double_complex* args, double_complex* retval) except 0:181py_args = []182cdef int i183for i from 0 <= i < n_args:184py_args.append(dz_to_CDE(args[i]))185py_result = fn(*py_args)186cdef ComplexDoubleElement result187if isinstance(py_result, ComplexDoubleElement):188result = <ComplexDoubleElement>py_result189else:190result = CDF(py_result)191retval[0] = CDE_to_dz(result)192return 1193"""[1:])194195instrs = [196InstrSpec('load_arg', pg('A[D]', 'S'),197code='o0 = i0;'),198InstrSpec('load_const', pg('C[D]', 'S'),199code='o0 = i0;'),200InstrSpec('return', pg('S', ''),201code='return i0;'),202InstrSpec('py_call', pg('P[D]S@D', 'S'),203uses_error_handler=True,204code="""205if (!cdf_py_call_helper(i0, n_i1, i1, &o0)) {206goto error;207}208""")209]210for name, op in [('add', '+'), ('sub', '-'),211('mul', '*'), ('div', '/'),212('truediv', '/')]:213instrs.append(instr_infix(name, pg('SS', 'S'), op))214instrs.append(instr_funcall_2args('pow', pg('SS', 'S'), 'cpow'))215instrs.append(instr_funcall_2args('ipow', pg('SD', 'S'), 'cpow_int'))216for (name, op) in [('neg', '-i0'), ('invert', '1/i0'),217('abs', 'cabs(i0)')]:218instrs.append(instr_unary(name, pg('S', 'S'), op))219for name in ['sqrt', 'sin', 'cos', 'tan',220'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',221'asinh', 'acosh', 'atanh', 'exp', 'log']:222instrs.append(instr_unary(name, pg('S', 'S'), "c%s(i0)" % name))223self.instr_descs = instrs224self._set_opcodes()225# supported for exponents that fit in an int226self.ipow_range = (int(-2**31), int(2**31 - 1))227228229