Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sage
Path: blob/develop/src/sage_setup/autogen/interpreters/internal/specs/cc.py
7417 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
# https://www.gnu.org/licenses/
10
# ****************************************************************************
11
from ..instructions import (
12
InstrSpec,
13
instr_funcall_1arg_mpc,
14
instr_funcall_2args_mpc,
15
params_gen,
16
)
17
from ..memory import MemoryChunk, MemoryChunkConstants
18
from ..storage import ty_mpc, ty_python
19
from ..utils import je
20
from ..utils import reindent_lines as ri
21
from .base import StackInterpreter
22
from .python import MemoryChunkPyConstant
23
24
25
class MemoryChunkCCRetval(MemoryChunk):
26
r"""
27
A special-purpose memory chunk, for dealing with the return value
28
of the CC-based interpreter.
29
"""
30
31
def declare_class_members(self):
32
r"""
33
Return a string giving the declarations of the class members
34
in a wrapper class for this memory chunk.
35
36
EXAMPLES::
37
38
sage: from sage_setup.autogen.interpreters.internal import *
39
sage: from sage_setup.autogen.interpreters.internal.specs.cc import *
40
sage: mc = MemoryChunkCCRetval('retval', ty_mpc)
41
sage: mc.declare_class_members()
42
''
43
"""
44
return ""
45
46
def declare_call_locals(self):
47
r"""
48
Return a string to put in the __call__ method of a wrapper
49
class using this memory chunk, to allocate local variables.
50
51
EXAMPLES::
52
53
sage: from sage_setup.autogen.interpreters.internal import *
54
sage: from sage_setup.autogen.interpreters.internal.specs.cc import *
55
sage: mc = MemoryChunkCCRetval('retval', ty_mpc)
56
sage: mc.declare_call_locals()
57
' cdef ComplexNumber retval = (self.domain_element._new())\n'
58
"""
59
return je(ri(8,
60
"""
61
cdef ComplexNumber {{ myself.name }} = (self.domain_element._new())
62
"""), myself=self)
63
64
def declare_parameter(self):
65
r"""
66
Return the string to use to declare the interpreter parameter
67
corresponding to this memory chunk.
68
69
EXAMPLES::
70
71
sage: from sage_setup.autogen.interpreters.internal import *
72
sage: from sage_setup.autogen.interpreters.internal.specs.cc import *
73
sage: mc = MemoryChunkCCRetval('retval', ty_mpc)
74
sage: mc.declare_parameter()
75
'mpc_t retval'
76
"""
77
return '%s %s' % (self.storage_type.c_reference_type(), self.name)
78
79
def pass_argument(self):
80
r"""
81
Return the string to pass the argument corresponding to this
82
memory chunk to the interpreter.
83
84
EXAMPLES::
85
86
sage: from sage_setup.autogen.interpreters.internal import *
87
sage: from sage_setup.autogen.interpreters.internal.specs.cc import *
88
sage: mc = MemoryChunkCCRetval('retval', ty_mpc)
89
sage: mc.pass_argument()
90
'(<mpc_t>(retval.__re))'
91
"""
92
return je("""(<mpc_t>({{ myself.name }}.__re))""", myself=self)
93
94
def pass_call_c_argument(self):
95
r"""
96
Return the string to pass the argument corresponding to this
97
memory chunk to the interpreter, for use in the call_c method.
98
99
EXAMPLES::
100
101
sage: from sage_setup.autogen.interpreters.internal import *
102
sage: from sage_setup.autogen.interpreters.internal.specs.cc import *
103
sage: mc = MemoryChunkCCRetval('retval', ty_mpc)
104
sage: mc.pass_call_c_argument()
105
'result'
106
"""
107
return "result"
108
109
110
class CCInterpreter(StackInterpreter):
111
r"""
112
A subclass of StackInterpreter, specifying an interpreter over
113
MPFR arbitrary-precision floating-point numbers.
114
"""
115
116
name = 'cc'
117
118
def __init__(self):
119
r"""
120
Initialize a CCInterpreter.
121
122
EXAMPLES::
123
124
sage: from sage_setup.autogen.interpreters.internal import *
125
sage: from sage_setup.autogen.interpreters.internal.specs.cc import *
126
sage: interp = CCInterpreter()
127
sage: interp.name
128
'cc'
129
sage: interp.mc_py_constants
130
{MC:py_constants}
131
sage: interp.chunks
132
[{MC:args}, {MC:retval}, {MC:constants}, {MC:py_constants}, {MC:stack}, {MC:code}, {MC:domain}]
133
sage: interp.pg('A[D]', 'S')
134
([({MC:args}, {MC:code}, None)], [({MC:stack}, None, None)])
135
sage: instrs = dict([(ins.name, ins) for ins in interp.instr_descs])
136
sage: instrs['add']
137
add: SS->S = 'mpc_add(o0, i0, i1, MPC_RNDNN);'
138
sage: instrs['py_call']
139
py_call: *->S = '\n if (!cc_py_call...goto error;\n}\n'
140
141
That py_call instruction is particularly interesting, and
142
demonstrates a useful technique to let you use Cython code
143
in an interpreter. Let's look more closely::
144
145
sage: print(instrs['py_call'].code)
146
<BLANKLINE>
147
if (!cc_py_call_helper(domain, i0, n_i1, i1, o0)) {
148
goto error;
149
}
150
<BLANKLINE>
151
152
This instruction makes use of the function cc_py_call_helper,
153
which is declared::
154
155
sage: print(interp.c_header)
156
<BLANKLINE>
157
#include <mpc.h>
158
<BLANKLINE>
159
160
So instructions where you need to interact with Python can
161
call back into Cython code fairly easily.
162
"""
163
164
mc_retval = MemoryChunkCCRetval('retval', ty_mpc)
165
super().__init__(ty_mpc, mc_retval=mc_retval)
166
self.err_return = '0'
167
self.mc_py_constants = MemoryChunkConstants('py_constants', ty_python)
168
self.mc_domain = MemoryChunkPyConstant('domain')
169
self.chunks = [self.mc_args, self.mc_retval, self.mc_constants,
170
self.mc_py_constants,
171
self.mc_stack, self.mc_code, self.mc_domain]
172
pg = params_gen(A=self.mc_args, C=self.mc_constants, D=self.mc_code,
173
S=self.mc_stack,
174
P=self.mc_py_constants)
175
self.pg = pg
176
self.c_header = ri(0,
177
'''
178
#include <mpc.h>
179
''')
180
181
self.pxd_header = ri(0,
182
"""
183
from sage.rings.real_mpfr cimport RealNumber
184
from sage.libs.mpfr cimport *
185
from sage.rings.complex_mpfr cimport ComplexNumber
186
from sage.libs.mpc cimport *
187
""")
188
189
self.pyx_header = ri(0,
190
"""\
191
# distutils: libraries = mpfr mpc gmp
192
193
cdef public bint cc_py_call_helper(object domain, object fn,
194
int n_args,
195
mpc_t* args, mpc_t retval) except 0:
196
py_args = []
197
cdef int i
198
cdef ComplexNumber ZERO=domain.zero()
199
cdef ComplexNumber cn
200
for i from 0 <= i < n_args:
201
cn = ZERO._new()
202
mpfr_set(cn.__re, mpc_realref(args[i]), MPFR_RNDN)
203
mpfr_set(cn.__im, mpc_imagref(args[i]), MPFR_RNDN)
204
py_args.append(cn)
205
cdef ComplexNumber result = domain(fn(*py_args))
206
mpc_set_fr_fr(retval, result.__re,result.__im, MPC_RNDNN)
207
return 1
208
""")
209
210
instrs = [
211
InstrSpec('load_arg', pg('A[D]', 'S'),
212
code='mpc_set(o0, i0, MPC_RNDNN);'),
213
InstrSpec('load_const', pg('C[D]', 'S'),
214
code='mpc_set(o0, i0, MPC_RNDNN);'),
215
InstrSpec('return', pg('S', ''),
216
code='mpc_set(retval, i0, MPC_RNDNN);\nreturn 1;\n'),
217
InstrSpec('py_call', pg('P[D]S@D', 'S'),
218
uses_error_handler=True,
219
code="""
220
if (!cc_py_call_helper(domain, i0, n_i1, i1, o0)) {
221
goto error;
222
}
223
""")
224
]
225
for (name, op) in [('add', 'mpc_add'), ('sub', 'mpc_sub'),
226
('mul', 'mpc_mul'), ('div', 'mpc_div'),
227
('pow', 'mpc_pow')]:
228
instrs.append(instr_funcall_2args_mpc(name, pg('SS', 'S'), op))
229
instrs.append(instr_funcall_2args_mpc('ipow', pg('SD', 'S'), 'mpc_pow_si'))
230
for name in ['neg',
231
'log', 'log10',
232
'exp',
233
'cos', 'sin', 'tan',
234
'acos', 'asin', 'atan',
235
'cosh', 'sinh', 'tanh',
236
'acosh', 'asinh', 'atanh']:
237
instrs.append(instr_funcall_1arg_mpc(name, pg('S', 'S'), 'mpc_' + name))
238
# mpc_ui_div constructs a temporary mpc_t and then calls mpc_div;
239
# it would probably be (slightly) faster to use a permanent copy
240
# of "one" (on the other hand, the constructed temporary copy is
241
# on the stack, so it's very likely to be in the cache).
242
instrs.append(InstrSpec('invert', pg('S', 'S'),
243
code='mpc_ui_div(o0, 1, i0, MPC_RNDNN);'))
244
self.instr_descs = instrs
245
self._set_opcodes()
246
# Supported for exponents that fit in a long, so we could use
247
# a much wider range on a 64-bit machine. On the other hand,
248
# it's easier to write the code this way, and constant integer
249
# exponents outside this range probably aren't very common anyway.
250
self.ipow_range = (int(-2**31), int(2**31-1))
251
252