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