compiled-knowledge 4.0.0a18__cp312-cp312-win_amd64.whl → 4.0.0a19__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of compiled-knowledge might be problematic. Click here for more details.
- ck/circuit/__init__.py +0 -3
- ck/circuit/_circuit_cy.cp312-win_amd64.pyd +0 -0
- ck/circuit/_circuit_cy.pxd +3 -4
- ck/circuit/_circuit_cy.pyx +80 -79
- ck/circuit_compiler/cython_vm_compiler/_compiler.cp312-win_amd64.pyd +0 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.pyx +188 -75
- ck/circuit_compiler/cython_vm_compiler/cython_vm_compiler.py +29 -4
- ck/circuit_compiler/support/circuit_analyser/__init__.py +13 -0
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.cp312-win_amd64.pyd +0 -0
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.pyx +98 -0
- ck/circuit_compiler/support/{circuit_analyser.py → circuit_analyser/_circuit_analyser_py.py} +14 -2
- ck/pgm_compiler/ace/__init__.py +1 -1
- ck/pgm_compiler/support/circuit_table/__init__.py +1 -0
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy.cp312-win_amd64.pyd +0 -0
- ck_demos/ace/demo_ace.py +5 -0
- {compiled_knowledge-4.0.0a18.dist-info → compiled_knowledge-4.0.0a19.dist-info}/METADATA +1 -1
- {compiled_knowledge-4.0.0a18.dist-info → compiled_knowledge-4.0.0a19.dist-info}/RECORD +20 -20
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy_cpp_verion.pyx +0 -601
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy_minimal_version.pyx +0 -311
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy_v4.0.0a17.pyx +0 -325
- {compiled_knowledge-4.0.0a18.dist-info → compiled_knowledge-4.0.0a19.dist-info}/WHEEL +0 -0
- {compiled_knowledge-4.0.0a18.dist-info → compiled_knowledge-4.0.0a19.dist-info}/licenses/LICENSE.txt +0 -0
- {compiled_knowledge-4.0.0a18.dist-info → compiled_knowledge-4.0.0a19.dist-info}/top_level.txt +0 -0
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Dict, Tuple
|
|
3
|
+
from typing import Dict, Tuple
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import ctypes as ct
|
|
7
7
|
|
|
8
8
|
from ck import circuit
|
|
9
|
-
from ck.circuit import OpNode
|
|
10
|
-
from ck.circuit_compiler.support.circuit_analyser import CircuitAnalysis
|
|
9
|
+
from ck.circuit import OpNode
|
|
10
|
+
from ck.circuit_compiler.support.circuit_analyser import CircuitAnalysis
|
|
11
11
|
from ck.program.raw_program import RawProgramFunction
|
|
12
12
|
from ck.utils.np_extras import NDArrayNumeric, DTypeNumeric
|
|
13
13
|
|
|
14
14
|
from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free
|
|
15
|
+
from cython.operator cimport dereference as deref, preincrement as incr, postdecrement
|
|
15
16
|
|
|
16
17
|
cimport numpy as cnp
|
|
17
|
-
cimport cython
|
|
18
18
|
|
|
19
19
|
cnp.import_array()
|
|
20
20
|
|
|
@@ -22,20 +22,34 @@ DTYPE_FLOAT64 = np.float64
|
|
|
22
22
|
ctypedef cnp.float64_t DTYPE_FLOAT64_t
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
ctypedef fused cvm_type:
|
|
26
|
+
double
|
|
27
|
+
float
|
|
28
|
+
int
|
|
29
|
+
long
|
|
30
|
+
short
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
DTYPE_TO_CVM_TYPE: Dict[DTypeNumeric, str] = {
|
|
33
|
+
np.float64: 'double',
|
|
34
|
+
np.float32: 'float',
|
|
35
|
+
np.intc: 'int',
|
|
36
|
+
np.long: 'long',
|
|
37
|
+
np.short: 'short',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def make_function(analysis: CircuitAnalysis, dtype: DTypeNumeric) -> Tuple[RawProgramFunction, int]:
|
|
31
42
|
"""
|
|
32
43
|
Make a RawProgram function that interprets the circuit.
|
|
33
44
|
|
|
45
|
+
Args:
|
|
46
|
+
analysis: A circuit analysis object defining the function.
|
|
47
|
+
dtype: a numpy data type that must be a key in the dictionary, DTYPE_TO_CVM_TYPE.
|
|
48
|
+
|
|
34
49
|
Returns:
|
|
35
50
|
(function, number_of_tmps)
|
|
36
51
|
"""
|
|
37
52
|
|
|
38
|
-
analysis: CircuitAnalysis = analyze_circuit(var_nodes, result_nodes)
|
|
39
53
|
cdef Instructions instructions
|
|
40
54
|
np_consts: NDArrayNumeric
|
|
41
55
|
instructions, np_consts = _make_instructions_from_analysis(analysis, dtype)
|
|
@@ -43,23 +57,79 @@ def make_function(
|
|
|
43
57
|
ptr_type = ct.POINTER(np.ctypeslib.as_ctypes_type(dtype))
|
|
44
58
|
c_np_consts = np_consts.ctypes.data_as(ptr_type)
|
|
45
59
|
|
|
60
|
+
cvm_type_name: str = DTYPE_TO_CVM_TYPE[dtype]
|
|
61
|
+
|
|
46
62
|
# RawProgramFunction = Callable[[ct.POINTER, ct.POINTER, ct.POINTER], None]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
if cvm_type_name == 'double':
|
|
64
|
+
def function(vars_in: ct.POINTER, tmps: ct.POINTER, result: ct.POINTER) -> None:
|
|
65
|
+
cdef size_t vars_in_addr = ct.cast(vars_in, ct.c_void_p).value
|
|
66
|
+
cdef size_t tmps_addr = ct.cast(tmps, ct.c_void_p).value
|
|
67
|
+
cdef size_t consts_addr = ct.cast(c_np_consts, ct.c_void_p).value
|
|
68
|
+
cdef size_t result_addr = ct.cast(result, ct.c_void_p).value
|
|
69
|
+
cvm[double](
|
|
70
|
+
<double *> vars_in_addr,
|
|
71
|
+
<double *> tmps_addr,
|
|
72
|
+
<double *> consts_addr,
|
|
73
|
+
<double *> result_addr,
|
|
74
|
+
instructions,
|
|
75
|
+
)
|
|
76
|
+
elif cvm_type_name == 'float':
|
|
77
|
+
def function(vars_in: ct.POINTER, tmps: ct.POINTER, result: ct.POINTER) -> None:
|
|
78
|
+
cdef size_t vars_in_addr = ct.cast(vars_in, ct.c_void_p).value
|
|
79
|
+
cdef size_t tmps_addr = ct.cast(tmps, ct.c_void_p).value
|
|
80
|
+
cdef size_t consts_addr = ct.cast(c_np_consts, ct.c_void_p).value
|
|
81
|
+
cdef size_t result_addr = ct.cast(result, ct.c_void_p).value
|
|
82
|
+
cvm[float](
|
|
83
|
+
<float *> vars_in_addr,
|
|
84
|
+
<float *> tmps_addr,
|
|
85
|
+
<float *> consts_addr,
|
|
86
|
+
<float *> result_addr,
|
|
87
|
+
instructions,
|
|
88
|
+
)
|
|
89
|
+
elif cvm_type_name == 'int':
|
|
90
|
+
def function(vars_in: ct.POINTER, tmps: ct.POINTER, result: ct.POINTER) -> None:
|
|
91
|
+
cdef size_t vars_in_addr = ct.cast(vars_in, ct.c_void_p).value
|
|
92
|
+
cdef size_t tmps_addr = ct.cast(tmps, ct.c_void_p).value
|
|
93
|
+
cdef size_t consts_addr = ct.cast(c_np_consts, ct.c_void_p).value
|
|
94
|
+
cdef size_t result_addr = ct.cast(result, ct.c_void_p).value
|
|
95
|
+
cvm[int](
|
|
96
|
+
<int *> vars_in_addr,
|
|
97
|
+
<int *> tmps_addr,
|
|
98
|
+
<int *> consts_addr,
|
|
99
|
+
<int *> result_addr,
|
|
100
|
+
instructions,
|
|
101
|
+
)
|
|
102
|
+
elif cvm_type_name == 'long':
|
|
103
|
+
def function(vars_in: ct.POINTER, tmps: ct.POINTER, result: ct.POINTER) -> None:
|
|
104
|
+
cdef size_t vars_in_addr = ct.cast(vars_in, ct.c_void_p).value
|
|
105
|
+
cdef size_t tmps_addr = ct.cast(tmps, ct.c_void_p).value
|
|
106
|
+
cdef size_t consts_addr = ct.cast(c_np_consts, ct.c_void_p).value
|
|
107
|
+
cdef size_t result_addr = ct.cast(result, ct.c_void_p).value
|
|
108
|
+
cvm[long](
|
|
109
|
+
<long *> vars_in_addr,
|
|
110
|
+
<long *> tmps_addr,
|
|
111
|
+
<long *> consts_addr,
|
|
112
|
+
<long *> result_addr,
|
|
113
|
+
instructions,
|
|
114
|
+
)
|
|
115
|
+
elif cvm_type_name == 'short':
|
|
116
|
+
def function(vars_in: ct.POINTER, tmps: ct.POINTER, result: ct.POINTER) -> None:
|
|
117
|
+
cdef size_t vars_in_addr = ct.cast(vars_in, ct.c_void_p).value
|
|
118
|
+
cdef size_t tmps_addr = ct.cast(tmps, ct.c_void_p).value
|
|
119
|
+
cdef size_t consts_addr = ct.cast(c_np_consts, ct.c_void_p).value
|
|
120
|
+
cdef size_t result_addr = ct.cast(result, ct.c_void_p).value
|
|
121
|
+
cvm[short](
|
|
122
|
+
<short *> vars_in_addr,
|
|
123
|
+
<short *> tmps_addr,
|
|
124
|
+
<short *> consts_addr,
|
|
125
|
+
<short *> result_addr,
|
|
126
|
+
instructions,
|
|
127
|
+
)
|
|
128
|
+
else:
|
|
129
|
+
raise ValueError(f'cvm_type_name unexpected: {cvm_type_name!r}')
|
|
59
130
|
|
|
60
131
|
return function, len(analysis.op_to_tmp)
|
|
61
132
|
|
|
62
|
-
|
|
63
133
|
# VM instructions
|
|
64
134
|
cdef int ADD = circuit.ADD
|
|
65
135
|
cdef int MUL = circuit.MUL
|
|
@@ -71,14 +141,10 @@ cdef int TMPS = 1
|
|
|
71
141
|
cdef int CONSTS = 2
|
|
72
142
|
cdef int RESULT = 3
|
|
73
143
|
|
|
74
|
-
|
|
75
144
|
cdef tuple[Instructions, cnp.ndarray] _make_instructions_from_analysis(
|
|
76
145
|
object analysis: CircuitAnalysis,
|
|
77
146
|
object dtype: DTypeNumeric,
|
|
78
|
-
):
|
|
79
|
-
if dtype != np.float64:
|
|
80
|
-
raise RuntimeError(f'only DType {np.float64} currently supported')
|
|
81
|
-
|
|
147
|
+
):
|
|
82
148
|
# Store const values in a numpy array
|
|
83
149
|
node_to_const_idx: Dict[int, int] = {
|
|
84
150
|
id(node): i
|
|
@@ -89,7 +155,7 @@ cdef tuple[Instructions, cnp.ndarray] _make_instructions_from_analysis(
|
|
|
89
155
|
np_consts[i] = node.value
|
|
90
156
|
|
|
91
157
|
# Where to get input values for each possible node.
|
|
92
|
-
cdef dict[int, ElementID] node_to_element
|
|
158
|
+
cdef dict[int, ElementID] node_to_element = {}
|
|
93
159
|
# const nodes
|
|
94
160
|
for node_id, const_idx in node_to_const_idx.items():
|
|
95
161
|
node_to_element[node_id] = ElementID(CONSTS, const_idx)
|
|
@@ -121,19 +187,16 @@ cdef tuple[Instructions, cnp.ndarray] _make_instructions_from_analysis(
|
|
|
121
187
|
|
|
122
188
|
return instructions, np_consts
|
|
123
189
|
|
|
124
|
-
|
|
125
190
|
cdef struct ElementID:
|
|
126
191
|
int array # VARS, TMPS, CONSTS, RESULT
|
|
127
192
|
int index # index into the array
|
|
128
193
|
|
|
129
|
-
|
|
130
194
|
cdef struct Instruction:
|
|
131
195
|
int symbol # ADD, MUL, COPY
|
|
132
196
|
Py_ssize_t num_args
|
|
133
197
|
ElementID* args
|
|
134
198
|
ElementID dest
|
|
135
199
|
|
|
136
|
-
|
|
137
200
|
cdef class Instructions:
|
|
138
201
|
cdef Instruction* instructions
|
|
139
202
|
cdef int allocated
|
|
@@ -142,14 +205,14 @@ cdef class Instructions:
|
|
|
142
205
|
def __init__(self) -> None:
|
|
143
206
|
self.num_instructions = 0
|
|
144
207
|
self.allocated = 64
|
|
145
|
-
self.instructions = <Instruction*> PyMem_Malloc(self.allocated * sizeof(Instruction))
|
|
208
|
+
self.instructions = <Instruction *> PyMem_Malloc(self.allocated * sizeof(Instruction))
|
|
146
209
|
|
|
147
210
|
cdef void append_copy(
|
|
148
211
|
self,
|
|
149
212
|
ElementID src,
|
|
150
213
|
ElementID dest,
|
|
151
214
|
) except*:
|
|
152
|
-
c_args = <ElementID*> PyMem_Malloc(sizeof(ElementID))
|
|
215
|
+
c_args = <ElementID *> PyMem_Malloc(sizeof(ElementID))
|
|
153
216
|
if not c_args:
|
|
154
217
|
raise MemoryError()
|
|
155
218
|
|
|
@@ -161,7 +224,7 @@ cdef class Instructions:
|
|
|
161
224
|
cdef Py_ssize_t num_args = len(args)
|
|
162
225
|
|
|
163
226
|
# Create the instruction arguments array
|
|
164
|
-
c_args = <ElementID*> PyMem_Malloc(num_args * sizeof(ElementID))
|
|
227
|
+
c_args = <ElementID *> PyMem_Malloc(num_args * sizeof(ElementID))
|
|
165
228
|
if not c_args:
|
|
166
229
|
raise MemoryError()
|
|
167
230
|
|
|
@@ -174,8 +237,7 @@ cdef class Instructions:
|
|
|
174
237
|
|
|
175
238
|
self._append(symbol, num_args, c_args, dest)
|
|
176
239
|
|
|
177
|
-
|
|
178
|
-
cdef void _append(self, int symbol, Py_ssize_t num_args, ElementID* c_args, ElementID dest) except *:
|
|
240
|
+
cdef void _append(self, int symbol, Py_ssize_t num_args, ElementID * c_args, ElementID dest) except*:
|
|
179
241
|
cdef int i
|
|
180
242
|
|
|
181
243
|
cdef int num_instructions = self.num_instructions
|
|
@@ -184,7 +246,7 @@ cdef class Instructions:
|
|
|
184
246
|
cdef int allocated = self.allocated
|
|
185
247
|
if num_instructions == allocated:
|
|
186
248
|
allocated *= 2
|
|
187
|
-
self.instructions = <Instruction*> PyMem_Realloc(
|
|
249
|
+
self.instructions = <Instruction *> PyMem_Realloc(
|
|
188
250
|
self.instructions,
|
|
189
251
|
allocated * sizeof(Instruction),
|
|
190
252
|
)
|
|
@@ -202,66 +264,117 @@ cdef class Instructions:
|
|
|
202
264
|
self.num_instructions = num_instructions + 1
|
|
203
265
|
|
|
204
266
|
def __dealloc__(self) -> None:
|
|
205
|
-
cdef Instruction* instructions = self.instructions
|
|
267
|
+
cdef Instruction * instructions = self.instructions
|
|
206
268
|
if instructions:
|
|
207
269
|
for i in range(self.num_instructions):
|
|
208
270
|
PyMem_Free(instructions[i].args)
|
|
209
271
|
PyMem_Free(instructions)
|
|
210
272
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
double* result,
|
|
220
|
-
Instructions instructions,
|
|
221
|
-
) except *:
|
|
222
|
-
# Core virtual machine (for dtype float64).
|
|
273
|
+
cdef void cvm(
|
|
274
|
+
cvm_type * vars_in,
|
|
275
|
+
cvm_type * tmps,
|
|
276
|
+
cvm_type * consts,
|
|
277
|
+
cvm_type * result,
|
|
278
|
+
Instructions instructions,
|
|
279
|
+
):
|
|
280
|
+
# Core virtual machine (for fused type 'cvm_type').
|
|
223
281
|
|
|
224
282
|
cdef int symbol
|
|
225
|
-
cdef
|
|
226
|
-
cdef
|
|
227
|
-
cdef ElementID*
|
|
228
|
-
cdef ElementID
|
|
283
|
+
cdef cvm_type accumulator
|
|
284
|
+
cdef ElementID * args
|
|
285
|
+
cdef ElementID * args_end
|
|
286
|
+
cdef ElementID * dest
|
|
229
287
|
|
|
230
288
|
# Index the four arrays by constants VARS, TMPS, CONSTS, and RESULT
|
|
231
|
-
cdef (
|
|
289
|
+
cdef (cvm_type *) arrays[4]
|
|
232
290
|
arrays[VARS] = vars_in
|
|
233
291
|
arrays[TMPS] = tmps
|
|
234
292
|
arrays[CONSTS] = consts
|
|
235
293
|
arrays[RESULT] = result
|
|
236
294
|
|
|
237
|
-
cdef Instruction* instruction_ptr = instructions.instructions
|
|
238
|
-
cdef
|
|
295
|
+
cdef Instruction * instruction_ptr = instructions.instructions
|
|
296
|
+
cdef Instruction * instruction_end = instruction_ptr + instructions.num_instructions
|
|
239
297
|
|
|
240
|
-
while
|
|
241
|
-
num_instructions -= 1
|
|
298
|
+
while instruction_ptr < instruction_end:
|
|
242
299
|
|
|
243
300
|
symbol = instruction_ptr.symbol
|
|
244
301
|
args = instruction_ptr.args
|
|
245
302
|
|
|
246
|
-
|
|
247
|
-
accumulator = arrays[elem.array][elem.index]
|
|
303
|
+
accumulator = arrays[args.array][args.index]
|
|
248
304
|
|
|
249
305
|
if symbol == ADD:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
306
|
+
args_end = args + instruction_ptr.num_args
|
|
307
|
+
incr(args)
|
|
308
|
+
while args < args_end:
|
|
309
|
+
accumulator += arrays[args.array][args.index]
|
|
310
|
+
incr(args)
|
|
255
311
|
elif symbol == MUL:
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
312
|
+
args_end = args + instruction_ptr.num_args
|
|
313
|
+
incr(args)
|
|
314
|
+
while args < args_end:
|
|
315
|
+
accumulator *= arrays[args.array][args.index]
|
|
316
|
+
incr(args)
|
|
261
317
|
# else symbol == COPY, nothing to do
|
|
262
318
|
|
|
263
|
-
|
|
264
|
-
arrays[
|
|
319
|
+
dest = &instruction_ptr.dest
|
|
320
|
+
arrays[dest.array][dest.index] = accumulator
|
|
265
321
|
|
|
266
322
|
# Advance the instruction pointer
|
|
267
|
-
|
|
323
|
+
incr(instruction_ptr)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# This is the older 4.0.0a17 version which seems to be 10% faster sometimes!
|
|
327
|
+
#
|
|
328
|
+
# cdef void cvm(
|
|
329
|
+
# cvm_type * vars_in,
|
|
330
|
+
# cvm_type * tmps,
|
|
331
|
+
# cvm_type * consts,
|
|
332
|
+
# cvm_type * result,
|
|
333
|
+
# Instructions instructions,
|
|
334
|
+
# ):
|
|
335
|
+
# # Core virtual machine (for fused type 'cvm_type').
|
|
336
|
+
#
|
|
337
|
+
# cdef int symbol
|
|
338
|
+
# cdef Py_ssize_t i
|
|
339
|
+
# cdef cvm_type accumulator
|
|
340
|
+
# cdef ElementID* args
|
|
341
|
+
# cdef ElementID elem
|
|
342
|
+
#
|
|
343
|
+
# # Index the four arrays by constants VARS, TMPS, CONSTS, and RESULT
|
|
344
|
+
# cdef (cvm_type*) arrays[4]
|
|
345
|
+
# arrays[VARS] = vars_in
|
|
346
|
+
# arrays[TMPS] = tmps
|
|
347
|
+
# arrays[CONSTS] = consts
|
|
348
|
+
# arrays[RESULT] = result
|
|
349
|
+
#
|
|
350
|
+
# cdef Instruction* instruction_ptr = instructions.instructions
|
|
351
|
+
# cdef Py_ssize_t num_instructions = instructions.num_instructions
|
|
352
|
+
#
|
|
353
|
+
# while num_instructions > 0:
|
|
354
|
+
# num_instructions -= 1
|
|
355
|
+
#
|
|
356
|
+
# symbol = instruction_ptr.symbol
|
|
357
|
+
# args = instruction_ptr.args
|
|
358
|
+
#
|
|
359
|
+
# elem = args[0]
|
|
360
|
+
# accumulator = arrays[elem.array][elem.index]
|
|
361
|
+
#
|
|
362
|
+
# if symbol == ADD:
|
|
363
|
+
# i = instruction_ptr.num_args
|
|
364
|
+
# while i > 1:
|
|
365
|
+
# i -= 1
|
|
366
|
+
# elem = args[i]
|
|
367
|
+
# accumulator += arrays[elem.array][elem.index]
|
|
368
|
+
# elif symbol == MUL:
|
|
369
|
+
# i = instruction_ptr.num_args
|
|
370
|
+
# while i > 1:
|
|
371
|
+
# i -= 1
|
|
372
|
+
# elem = args[i]
|
|
373
|
+
# accumulator *= arrays[elem.array][elem.index]
|
|
374
|
+
# # else symbol == COPY, nothing to do
|
|
375
|
+
#
|
|
376
|
+
# elem = instruction_ptr.dest
|
|
377
|
+
# arrays[elem.array][elem.index] = accumulator
|
|
378
|
+
#
|
|
379
|
+
# # Advance the instruction pointer
|
|
380
|
+
# instruction_ptr = &(instruction_ptr[1])
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
from typing import Optional, Sequence
|
|
1
|
+
from typing import Optional, Sequence, Tuple
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
|
|
5
5
|
from ck.circuit import CircuitNode, Circuit, VarNode
|
|
6
6
|
from ck.circuit_compiler.support.input_vars import InferVars, InputVars, infer_input_vars
|
|
7
|
-
from ck.program.raw_program import RawProgram
|
|
7
|
+
from ck.program.raw_program import RawProgram, RawProgramFunction
|
|
8
8
|
from ck.utils.np_extras import DTypeNumeric
|
|
9
|
-
from .
|
|
9
|
+
from . import _compiler
|
|
10
|
+
from ..support.circuit_analyser import CircuitAnalysis, analyze_circuit
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def compile_circuit(
|
|
@@ -31,7 +32,11 @@ def compile_circuit(
|
|
|
31
32
|
Raises:
|
|
32
33
|
ValueError: if the circuit is unknown, but it is needed.
|
|
33
34
|
ValueError: if not all nodes are from the same circuit.
|
|
35
|
+
ValueError: if the given dtype is not supported.
|
|
34
36
|
"""
|
|
37
|
+
if dtype not in _compiler.DTYPE_TO_CVM_TYPE.keys():
|
|
38
|
+
raise ValueError(f'dtype not supported: {dtype!r}')
|
|
39
|
+
|
|
35
40
|
in_vars: Sequence[VarNode] = infer_input_vars(circuit, result, input_vars)
|
|
36
41
|
return CythonRawProgram(in_vars, result, dtype)
|
|
37
42
|
|
|
@@ -70,7 +75,7 @@ class CythonRawProgram(RawProgram):
|
|
|
70
75
|
'number_of_vars': self.number_of_vars,
|
|
71
76
|
'number_of_tmps': self.number_of_tmps,
|
|
72
77
|
'number_of_results': self.number_of_results,
|
|
73
|
-
'var_indices':self.var_indices,
|
|
78
|
+
'var_indices': self.var_indices,
|
|
74
79
|
#
|
|
75
80
|
'in_vars': self.in_vars,
|
|
76
81
|
'result': self.result,
|
|
@@ -94,3 +99,23 @@ class CythonRawProgram(RawProgram):
|
|
|
94
99
|
result_nodes=self.result,
|
|
95
100
|
dtype=self.dtype,
|
|
96
101
|
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _make_function(
|
|
105
|
+
var_nodes: Sequence[VarNode],
|
|
106
|
+
result_nodes: Sequence[CircuitNode],
|
|
107
|
+
dtype: DTypeNumeric,
|
|
108
|
+
) -> Tuple[RawProgramFunction, int]:
|
|
109
|
+
"""
|
|
110
|
+
Make a RawProgram function that interprets the circuit.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
var_nodes: The chosen input variable nodes of the circuit.
|
|
114
|
+
result_nodes: The chosen output result nodes of the circuit.
|
|
115
|
+
dtype: a numpy data type that must be a key in the dictionary, DTYPE_TO_CVM_TYPE.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
(function, number_of_tmps)
|
|
119
|
+
"""
|
|
120
|
+
analysis: CircuitAnalysis = analyze_circuit(var_nodes, result_nodes)
|
|
121
|
+
return _compiler.make_function(analysis, dtype)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# There are two implementations of the `circuit_analyser` module are provided
|
|
2
|
+
# for developer R&D purposes. One is pure Python and the other is Cython.
|
|
3
|
+
# Which implementation is used can be selected here.
|
|
4
|
+
#
|
|
5
|
+
# A similar selection can be made for the `circuit` module.
|
|
6
|
+
# Note that if the Cython implementation is chosen for `circuit_analyser` then
|
|
7
|
+
# the Cython implementation must be chosen for `circuit`.
|
|
8
|
+
|
|
9
|
+
# from ._circuit_analyser_py import (
|
|
10
|
+
from ._circuit_analyser_cy import (
|
|
11
|
+
CircuitAnalysis,
|
|
12
|
+
analyze_circuit,
|
|
13
|
+
)
|
|
Binary file
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List, Dict, Sequence, Set
|
|
3
|
+
|
|
4
|
+
from ck.circuit._circuit_cy cimport Circuit, OpNode, VarNode, CircuitNode, ConstNode
|
|
5
|
+
from cython.operator cimport postincrement
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class CircuitAnalysis:
|
|
10
|
+
"""
|
|
11
|
+
A data structure representing the analysis of a function defined by
|
|
12
|
+
a circuit which chosen input variables and output result nodes.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
var_nodes: Sequence[VarNode] # specified input var nodes
|
|
16
|
+
result_nodes: Sequence[CircuitNode] # specified result nodes
|
|
17
|
+
op_nodes: Sequence[OpNode] # in-use op nodes, in computation order
|
|
18
|
+
const_nodes: Sequence[ConstNode] # in_use const nodes, in arbitrary order
|
|
19
|
+
op_to_result: Dict[int, int] # op nodes in the result, op_node = result[idx]: id(op_node) -> idx
|
|
20
|
+
op_to_tmp: Dict[int, int] # op nodes needing tmp memory, using tmp[idx]: id(op_node) -> idx
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def analyze_circuit(
|
|
24
|
+
var_nodes: Sequence[VarNode],
|
|
25
|
+
result_nodes: Sequence[CircuitNode],
|
|
26
|
+
) -> CircuitAnalysis:
|
|
27
|
+
"""
|
|
28
|
+
Analyzes a circuit as a function from var_nodes to result_nodes,
|
|
29
|
+
returning a CircuitAnalysis object.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
var_nodes: The chosen input variable nodes of the circuit.
|
|
33
|
+
result_nodes: The chosen output result nodes of the circuit.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
A CircuitAnalysis object.
|
|
37
|
+
"""
|
|
38
|
+
cdef list[CircuitNode] results_list = list(result_nodes)
|
|
39
|
+
|
|
40
|
+
# What op nodes are in use
|
|
41
|
+
cdef list[OpNode] op_nodes = _reachable_op_nodes(results_list)
|
|
42
|
+
|
|
43
|
+
# What constant values are in use
|
|
44
|
+
cdef set[int] seen_const_nodes = set()
|
|
45
|
+
cdef list[ConstNode] const_nodes = []
|
|
46
|
+
|
|
47
|
+
def _register_const(_node: ConstNode) -> None:
|
|
48
|
+
nonlocal seen_const_nodes
|
|
49
|
+
nonlocal const_nodes
|
|
50
|
+
_node_id: int = id(_node)
|
|
51
|
+
if _node_id not in seen_const_nodes:
|
|
52
|
+
const_nodes.append(_node)
|
|
53
|
+
seen_const_nodes.add(_node_id)
|
|
54
|
+
|
|
55
|
+
# Register all the used constants
|
|
56
|
+
for op_node in op_nodes:
|
|
57
|
+
for node in op_node.args:
|
|
58
|
+
if isinstance(node, ConstNode):
|
|
59
|
+
_register_const(node)
|
|
60
|
+
for node in results_list:
|
|
61
|
+
if isinstance(node, ConstNode):
|
|
62
|
+
_register_const(node)
|
|
63
|
+
for node in var_nodes:
|
|
64
|
+
if node.is_const():
|
|
65
|
+
_register_const(node.const)
|
|
66
|
+
|
|
67
|
+
# What op nodes are in the result.
|
|
68
|
+
# Dict op_to_result maps id(OpNode) to result index.
|
|
69
|
+
cdef dict[int, int] op_to_result = {
|
|
70
|
+
id(node): i
|
|
71
|
+
for i, node in enumerate(result_nodes)
|
|
72
|
+
if isinstance(node, OpNode)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Assign all other op nodes to a tmp slot.
|
|
76
|
+
# Dict op_to_tmp maps id(OpNode) to tmp index.
|
|
77
|
+
cdef int tmp_idx = 0
|
|
78
|
+
op_to_tmp: Dict[int, int] = {
|
|
79
|
+
id(op_node): postincrement(tmp_idx)
|
|
80
|
+
for op_node in op_nodes
|
|
81
|
+
if id(op_node) not in op_to_result
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return CircuitAnalysis(
|
|
85
|
+
var_nodes=var_nodes,
|
|
86
|
+
result_nodes=result_nodes,
|
|
87
|
+
op_nodes=op_nodes,
|
|
88
|
+
const_nodes=const_nodes,
|
|
89
|
+
op_to_result=op_to_result,
|
|
90
|
+
op_to_tmp=op_to_tmp,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
cdef list[OpNode] _reachable_op_nodes(list[CircuitNode] results):
|
|
95
|
+
if len(results) == 0:
|
|
96
|
+
return []
|
|
97
|
+
cdef Circuit circuit = results[0].circuit
|
|
98
|
+
return circuit.find_reachable_op_nodes(results)
|
ck/circuit_compiler/support/{circuit_analyser.py → circuit_analyser/_circuit_analyser_py.py}
RENAMED
|
@@ -7,8 +7,13 @@ from ck.circuit import OpNode, VarNode, CircuitNode, ConstNode
|
|
|
7
7
|
|
|
8
8
|
@dataclass
|
|
9
9
|
class CircuitAnalysis:
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
"""
|
|
11
|
+
A data structure representing the analysis of a function defined by
|
|
12
|
+
a circuit which chosen input variables and output result nodes.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
var_nodes: Sequence[VarNode] # specified input var nodes
|
|
16
|
+
result_nodes: Sequence[CircuitNode] # specified result nodes
|
|
12
17
|
op_nodes: Sequence[OpNode] # in-use op nodes, in computation order
|
|
13
18
|
const_nodes: Sequence[ConstNode] # in_use const nodes, in arbitrary order
|
|
14
19
|
op_to_result: Dict[int, int] # op nodes in the result, op_node = result[idx]: id(op_node) -> idx
|
|
@@ -22,6 +27,13 @@ def analyze_circuit(
|
|
|
22
27
|
"""
|
|
23
28
|
Analyzes a circuit as a function from var_nodes to result_nodes,
|
|
24
29
|
returning a CircuitAnalysis object.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
var_nodes: The chosen input variable nodes of the circuit.
|
|
33
|
+
result_nodes: The chosen output result nodes of the circuit.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
A CircuitAnalysis object.
|
|
25
37
|
"""
|
|
26
38
|
# What op nodes are in use
|
|
27
39
|
op_nodes: List[OpNode] = (
|
ck/pgm_compiler/ace/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
from .ace import compile_pgm, copy_ace_to_default_location, default_ace_location
|
|
1
|
+
from .ace import compile_pgm, copy_ace_to_default_location, default_ace_location, ace_available
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# There are two implementations of the `circuit_table` module are provided
|
|
2
2
|
# for developer R&D purposes. One is pure Python and the other is Cython.
|
|
3
3
|
# Which implementation is used can be selected here.
|
|
4
|
+
#
|
|
4
5
|
# A similar selection can be made for the `circuit` module.
|
|
5
6
|
# Note that if the Cython implementation is chosen for `circuit_table` then
|
|
6
7
|
# the Cython implementation must be chosen for `circuit`.
|
|
Binary file
|
ck_demos/ace/demo_ace.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compiled-knowledge
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.0a19
|
|
4
4
|
Summary: A Python package for compiling and querying discrete probabilistic graphical models.
|
|
5
5
|
Author-email: Barry Drake <barry@compiledknowledge.org>
|
|
6
6
|
License-Expression: MIT
|