Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sage
Path: blob/develop/src/sage_setup/autogen/interpreters/internal/specs/rdf.py
4086 views
1
#*****************************************************************************
2
# Copyright (C) 2009 Carl Witty <[email protected]>
3
# Copyright (C) 2015 Jeroen Demeyer <[email protected]>
4
#
5
# This program is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation, either version 2 of the License, or
8
# (at your option) any later version.
9
# http://www.gnu.org/licenses/
10
#*****************************************************************************
11
12
from __future__ import print_function, absolute_import
13
14
from .base import StackInterpreter
15
from ..instructions import (params_gen, instr_infix, instr_funcall_2args,
16
instr_unary, InstrSpec)
17
from ..memory import MemoryChunkConstants
18
from ..storage import ty_double, ty_python
19
from ..utils import reindent_lines as ri
20
21
22
class RDFInterpreter(StackInterpreter):
23
r"""
24
A subclass of StackInterpreter, specifying an interpreter over
25
machine-floating-point values (C doubles). This is used for
26
both domain=RDF and domain=float; currently the only difference
27
between the two is the type of the value returned from the
28
wrapper (they use the same wrapper and interpreter).
29
"""
30
31
name = 'rdf'
32
33
def __init__(self):
34
r"""
35
Initialize an RDFInterpreter.
36
37
EXAMPLES::
38
39
sage: from sage_setup.autogen.interpreters.internal import *
40
sage: from sage_setup.autogen.interpreters.internal.specs.rdf import *
41
sage: interp = RDFInterpreter()
42
sage: interp.name
43
'rdf'
44
sage: interp.extra_class_members
45
'cdef object _domain\n'
46
sage: interp.extra_members_initialize
47
"self._domain = args['domain']\n"
48
sage: interp.adjust_retval
49
'self._domain'
50
sage: interp.mc_py_constants
51
{MC:py_constants}
52
sage: interp.chunks
53
[{MC:args}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}]
54
sage: interp.pg('A[D]', 'S')
55
([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])
56
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
57
sage: instrs['add']
58
add: SS->S = 'o0 = i0 + i1;'
59
sage: instrs['py_call']
60
py_call: *->S = '\nPyObject *py_arg...goto error;\n}\n'
61
62
Make sure that pow behaves reasonably::
63
64
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
65
sage: etb = ExpressionTreeBuilder(vars=('x','y'))
66
sage: x = etb.var('x')
67
sage: y = etb.var('y')
68
sage: ff = fast_callable(x^y, domain=RDF)
69
sage: ff(1.5, 3)
70
3.375
71
sage: ff(-2, 3)
72
-8.0
73
sage: ff(-2, 1/3)
74
Traceback (most recent call last):
75
...
76
ValueError: negative number to a fractional power not real
77
"""
78
79
super(RDFInterpreter, self).__init__(ty_double)
80
self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)
81
# This is a randomly chosen number. Whenever this number is
82
# returned, the wrapper has to check whether an exception actually
83
# happened, so if an expression evaluates to this number execution
84
# is slightly slower. Hopefully that won't happen too often :)
85
self.err_return = '-1094648009105371'
86
self.chunks = [self.mc_args, self.mc_constants, self.mc_py_constants,
87
self.mc_stack,
88
self.mc_code]
89
pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
90
S=self.mc_stack, P=self.mc_py_constants)
91
self.pg = pg
92
self.c_header = '#include <gsl/gsl_math.h>'
93
self.pyx_header = 'cimport sage.libs.gsl.math # Add dependency on GSL'
94
instrs = [
95
InstrSpec('load_arg', pg('A[D]', 'S'),
96
code='o0 = i0;'),
97
InstrSpec('load_const', pg('C[D]', 'S'),
98
code='o0 = i0;'),
99
InstrSpec('return', pg('S', ''),
100
code='return i0;'),
101
InstrSpec('py_call', pg('P[D]S@D', 'S'),
102
uses_error_handler=True,
103
code=ri(0, """
104
PyObject *py_args = PyTuple_New(n_i1);
105
if (py_args == NULL) goto error;
106
int i;
107
for (i = 0; i < n_i1; i++) {
108
PyObject *arg = PyFloat_FromDouble(i1[i]);
109
if (arg == NULL) {
110
Py_DECREF(py_args);
111
goto error;
112
}
113
PyTuple_SET_ITEM(py_args, i, arg);
114
}
115
PyObject *result = PyObject_CallObject(i0, py_args);
116
Py_DECREF(py_args);
117
if (result == NULL) goto error;
118
/* If result is not a float, then this will turn it into a float first. */
119
o0 = PyFloat_AsDouble(result);
120
Py_DECREF(result);
121
if (o0 == -1 && PyErr_Occurred()) {
122
goto error;
123
}
124
""")),
125
InstrSpec('pow', pg('SS', 'S'),
126
uses_error_handler=True,
127
code=ri(0, """
128
/* See python's pow in floatobject.c */
129
if (i0 == 0) o0 = 1.0;
130
else {
131
if (i0 < 0 && i1 != floor(i1)) {
132
PyErr_SetString(PyExc_ValueError, "negative number to a fractional power not real");
133
goto error;
134
}
135
o0 = pow(i0, i1);
136
}
137
"""))
138
]
139
for (name, op) in [('add', '+'), ('sub', '-'),
140
('mul', '*'), ('div', '/')]:
141
instrs.append(instr_infix(name, pg('SS', 'S'), op))
142
instrs.append(instr_funcall_2args('ipow', pg('SD', 'S'), 'gsl_pow_int'))
143
for (name, op) in [('neg', '-i0'), ('invert', '1/i0'),
144
('abs', 'fabs(i0)')]:
145
instrs.append(instr_unary(name, pg('S', 'S'), op))
146
for name in ['sqrt', 'ceil', 'floor', 'sin', 'cos', 'tan',
147
'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh',
148
'asinh', 'acosh', 'atanh', 'exp', 'log']:
149
instrs.append(instr_unary(name, pg('S', 'S'), "%s(i0)" % name))
150
self.instr_descs = instrs
151
self._set_opcodes()
152
# supported for exponents that fit in an int
153
self.ipow_range = (int(-2**31), int(2**31-1))
154
self.extra_class_members = "cdef object _domain\n"
155
self.extra_members_initialize = "self._domain = args['domain']\n"
156
self.adjust_retval = 'self._domain'
157
158