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