compiled-knowledge 4.0.0a20__cp312-cp312-musllinux_1_2_x86_64.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/__init__.py +0 -0
- ck/circuit/__init__.py +17 -0
- ck/circuit/_circuit_cy.c +37520 -0
- ck/circuit/_circuit_cy.cpython-312-x86_64-linux-musl.so +0 -0
- ck/circuit/_circuit_cy.pxd +32 -0
- ck/circuit/_circuit_cy.pyx +768 -0
- ck/circuit/_circuit_py.py +836 -0
- ck/circuit/tmp_const.py +74 -0
- ck/circuit_compiler/__init__.py +2 -0
- ck/circuit_compiler/circuit_compiler.py +26 -0
- ck/circuit_compiler/cython_vm_compiler/__init__.py +1 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.c +19821 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.cpython-312-x86_64-linux-musl.so +0 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.pyx +380 -0
- ck/circuit_compiler/cython_vm_compiler/cython_vm_compiler.py +121 -0
- ck/circuit_compiler/interpret_compiler.py +223 -0
- ck/circuit_compiler/llvm_compiler.py +388 -0
- ck/circuit_compiler/llvm_vm_compiler.py +546 -0
- ck/circuit_compiler/named_circuit_compilers.py +57 -0
- ck/circuit_compiler/support/__init__.py +0 -0
- ck/circuit_compiler/support/circuit_analyser/__init__.py +13 -0
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.c +10615 -0
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.cpython-312-x86_64-linux-musl.so +0 -0
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.pyx +98 -0
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_py.py +93 -0
- ck/circuit_compiler/support/input_vars.py +148 -0
- ck/circuit_compiler/support/llvm_ir_function.py +234 -0
- ck/example/__init__.py +53 -0
- ck/example/alarm.py +366 -0
- ck/example/asia.py +28 -0
- ck/example/binary_clique.py +32 -0
- ck/example/bow_tie.py +33 -0
- ck/example/cancer.py +37 -0
- ck/example/chain.py +38 -0
- ck/example/child.py +199 -0
- ck/example/clique.py +33 -0
- ck/example/cnf_pgm.py +39 -0
- ck/example/diamond_square.py +68 -0
- ck/example/earthquake.py +36 -0
- ck/example/empty.py +10 -0
- ck/example/hailfinder.py +539 -0
- ck/example/hepar2.py +628 -0
- ck/example/insurance.py +504 -0
- ck/example/loop.py +40 -0
- ck/example/mildew.py +38161 -0
- ck/example/munin.py +22982 -0
- ck/example/pathfinder.py +53747 -0
- ck/example/rain.py +39 -0
- ck/example/rectangle.py +161 -0
- ck/example/run.py +30 -0
- ck/example/sachs.py +129 -0
- ck/example/sprinkler.py +30 -0
- ck/example/star.py +44 -0
- ck/example/stress.py +64 -0
- ck/example/student.py +43 -0
- ck/example/survey.py +46 -0
- ck/example/triangle_square.py +54 -0
- ck/example/truss.py +49 -0
- ck/in_out/__init__.py +3 -0
- ck/in_out/parse_ace_lmap.py +216 -0
- ck/in_out/parse_ace_nnf.py +322 -0
- ck/in_out/parse_net.py +480 -0
- ck/in_out/parser_utils.py +185 -0
- ck/in_out/pgm_pickle.py +42 -0
- ck/in_out/pgm_python.py +268 -0
- ck/in_out/render_bugs.py +111 -0
- ck/in_out/render_net.py +177 -0
- ck/in_out/render_pomegranate.py +184 -0
- ck/pgm.py +3475 -0
- ck/pgm_circuit/__init__.py +1 -0
- ck/pgm_circuit/marginals_program.py +352 -0
- ck/pgm_circuit/mpe_program.py +237 -0
- ck/pgm_circuit/pgm_circuit.py +79 -0
- ck/pgm_circuit/program_with_slotmap.py +236 -0
- ck/pgm_circuit/slot_map.py +35 -0
- ck/pgm_circuit/support/__init__.py +0 -0
- ck/pgm_circuit/support/compile_circuit.py +83 -0
- ck/pgm_circuit/target_marginals_program.py +103 -0
- ck/pgm_circuit/wmc_program.py +323 -0
- ck/pgm_compiler/__init__.py +2 -0
- ck/pgm_compiler/ace/__init__.py +1 -0
- ck/pgm_compiler/ace/ace.py +299 -0
- ck/pgm_compiler/factor_elimination.py +395 -0
- ck/pgm_compiler/named_pgm_compilers.py +63 -0
- ck/pgm_compiler/pgm_compiler.py +19 -0
- ck/pgm_compiler/recursive_conditioning.py +231 -0
- ck/pgm_compiler/support/__init__.py +0 -0
- ck/pgm_compiler/support/circuit_table/__init__.py +17 -0
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy.c +16393 -0
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy.cpython-312-x86_64-linux-musl.so +0 -0
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy.pyx +332 -0
- ck/pgm_compiler/support/circuit_table/_circuit_table_py.py +304 -0
- ck/pgm_compiler/support/clusters.py +568 -0
- ck/pgm_compiler/support/factor_tables.py +406 -0
- ck/pgm_compiler/support/join_tree.py +332 -0
- ck/pgm_compiler/support/named_compiler_maker.py +43 -0
- ck/pgm_compiler/variable_elimination.py +91 -0
- ck/probability/__init__.py +0 -0
- ck/probability/empirical_probability_space.py +50 -0
- ck/probability/pgm_probability_space.py +32 -0
- ck/probability/probability_space.py +622 -0
- ck/program/__init__.py +3 -0
- ck/program/program.py +137 -0
- ck/program/program_buffer.py +180 -0
- ck/program/raw_program.py +67 -0
- ck/sampling/__init__.py +0 -0
- ck/sampling/forward_sampler.py +211 -0
- ck/sampling/marginals_direct_sampler.py +113 -0
- ck/sampling/sampler.py +62 -0
- ck/sampling/sampler_support.py +232 -0
- ck/sampling/uniform_sampler.py +72 -0
- ck/sampling/wmc_direct_sampler.py +171 -0
- ck/sampling/wmc_gibbs_sampler.py +153 -0
- ck/sampling/wmc_metropolis_sampler.py +165 -0
- ck/sampling/wmc_rejection_sampler.py +115 -0
- ck/utils/__init__.py +0 -0
- ck/utils/iter_extras.py +163 -0
- ck/utils/local_config.py +270 -0
- ck/utils/map_list.py +128 -0
- ck/utils/map_set.py +128 -0
- ck/utils/np_extras.py +51 -0
- ck/utils/random_extras.py +64 -0
- ck/utils/tmp_dir.py +94 -0
- ck_demos/__init__.py +0 -0
- ck_demos/ace/__init__.py +0 -0
- ck_demos/ace/copy_ace_to_ck.py +15 -0
- ck_demos/ace/demo_ace.py +49 -0
- ck_demos/all_demos.py +88 -0
- ck_demos/circuit/__init__.py +0 -0
- ck_demos/circuit/demo_circuit_dump.py +22 -0
- ck_demos/circuit/demo_derivatives.py +43 -0
- ck_demos/circuit_compiler/__init__.py +0 -0
- ck_demos/circuit_compiler/compare_circuit_compilers.py +32 -0
- ck_demos/circuit_compiler/show_llvm_program.py +26 -0
- ck_demos/pgm/__init__.py +0 -0
- ck_demos/pgm/demo_pgm_dump.py +18 -0
- ck_demos/pgm/demo_pgm_dump_stress.py +18 -0
- ck_demos/pgm/demo_pgm_string_rendering.py +15 -0
- ck_demos/pgm/show_examples.py +25 -0
- ck_demos/pgm_compiler/__init__.py +0 -0
- ck_demos/pgm_compiler/compare_pgm_compilers.py +63 -0
- ck_demos/pgm_compiler/demo_compiler_dump.py +60 -0
- ck_demos/pgm_compiler/demo_factor_elimination.py +47 -0
- ck_demos/pgm_compiler/demo_join_tree.py +25 -0
- ck_demos/pgm_compiler/demo_marginals_program.py +53 -0
- ck_demos/pgm_compiler/demo_mpe_program.py +55 -0
- ck_demos/pgm_compiler/demo_pgm_compiler.py +38 -0
- ck_demos/pgm_compiler/demo_recursive_conditioning.py +33 -0
- ck_demos/pgm_compiler/demo_variable_elimination.py +33 -0
- ck_demos/pgm_compiler/demo_wmc_program.py +29 -0
- ck_demos/pgm_compiler/time_fe_compiler.py +93 -0
- ck_demos/pgm_inference/__init__.py +0 -0
- ck_demos/pgm_inference/demo_inferencing_basic.py +188 -0
- ck_demos/pgm_inference/demo_inferencing_mpe_cancer.py +45 -0
- ck_demos/pgm_inference/demo_inferencing_wmc_and_mpe_sprinkler.py +154 -0
- ck_demos/pgm_inference/demo_inferencing_wmc_student.py +110 -0
- ck_demos/programs/__init__.py +0 -0
- ck_demos/programs/demo_program_buffer.py +24 -0
- ck_demos/programs/demo_program_multi.py +24 -0
- ck_demos/programs/demo_program_none.py +19 -0
- ck_demos/programs/demo_program_single.py +23 -0
- ck_demos/programs/demo_raw_program_interpreted.py +21 -0
- ck_demos/programs/demo_raw_program_llvm.py +21 -0
- ck_demos/sampling/__init__.py +0 -0
- ck_demos/sampling/check_sampler.py +71 -0
- ck_demos/sampling/demo_marginal_direct_sampler.py +40 -0
- ck_demos/sampling/demo_uniform_sampler.py +38 -0
- ck_demos/sampling/demo_wmc_direct_sampler.py +40 -0
- ck_demos/utils/__init__.py +0 -0
- ck_demos/utils/compare.py +120 -0
- ck_demos/utils/convert_network.py +45 -0
- ck_demos/utils/sample_model.py +216 -0
- ck_demos/utils/stop_watch.py +384 -0
- compiled_knowledge-4.0.0a20.dist-info/METADATA +50 -0
- compiled_knowledge-4.0.0a20.dist-info/RECORD +178 -0
- compiled_knowledge-4.0.0a20.dist-info/WHEEL +5 -0
- compiled_knowledge-4.0.0a20.dist-info/licenses/LICENSE.txt +21 -0
- compiled_knowledge-4.0.0a20.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Tuple
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import ctypes as ct
|
|
7
|
+
|
|
8
|
+
from ck import circuit
|
|
9
|
+
from ck.circuit import OpNode
|
|
10
|
+
from ck.circuit_compiler.support.circuit_analyser import CircuitAnalysis
|
|
11
|
+
from ck.program.raw_program import RawProgramFunction
|
|
12
|
+
from ck.utils.np_extras import NDArrayNumeric, DTypeNumeric
|
|
13
|
+
|
|
14
|
+
from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free
|
|
15
|
+
from cython.operator cimport dereference as deref, preincrement as incr, postdecrement
|
|
16
|
+
|
|
17
|
+
cimport numpy as cnp
|
|
18
|
+
|
|
19
|
+
cnp.import_array()
|
|
20
|
+
|
|
21
|
+
DTYPE_FLOAT64 = np.float64
|
|
22
|
+
ctypedef cnp.float64_t DTYPE_FLOAT64_t
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
ctypedef fused cvm_type:
|
|
26
|
+
double
|
|
27
|
+
float
|
|
28
|
+
int
|
|
29
|
+
long
|
|
30
|
+
short
|
|
31
|
+
|
|
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]:
|
|
42
|
+
"""
|
|
43
|
+
Make a RawProgram function that interprets the circuit.
|
|
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
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
(function, number_of_tmps)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
cdef Instructions instructions
|
|
54
|
+
np_consts: NDArrayNumeric
|
|
55
|
+
instructions, np_consts = _make_instructions_from_analysis(analysis, dtype)
|
|
56
|
+
|
|
57
|
+
ptr_type = ct.POINTER(np.ctypeslib.as_ctypes_type(dtype))
|
|
58
|
+
c_np_consts = np_consts.ctypes.data_as(ptr_type)
|
|
59
|
+
|
|
60
|
+
cvm_type_name: str = DTYPE_TO_CVM_TYPE[dtype]
|
|
61
|
+
|
|
62
|
+
# RawProgramFunction = Callable[[ct.POINTER, ct.POINTER, ct.POINTER], None]
|
|
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}')
|
|
130
|
+
|
|
131
|
+
return function, len(analysis.op_to_tmp)
|
|
132
|
+
|
|
133
|
+
# VM instructions
|
|
134
|
+
cdef int ADD = circuit.ADD
|
|
135
|
+
cdef int MUL = circuit.MUL
|
|
136
|
+
cdef int COPY = max(ADD, MUL) + 1
|
|
137
|
+
|
|
138
|
+
# VM arrays
|
|
139
|
+
cdef int VARS = 0
|
|
140
|
+
cdef int TMPS = 1
|
|
141
|
+
cdef int CONSTS = 2
|
|
142
|
+
cdef int RESULT = 3
|
|
143
|
+
|
|
144
|
+
cdef tuple[Instructions, cnp.ndarray] _make_instructions_from_analysis(
|
|
145
|
+
object analysis: CircuitAnalysis,
|
|
146
|
+
object dtype: DTypeNumeric,
|
|
147
|
+
):
|
|
148
|
+
# Store const values in a numpy array
|
|
149
|
+
node_to_const_idx: Dict[int, int] = {
|
|
150
|
+
id(node): i
|
|
151
|
+
for i, node in enumerate(analysis.const_nodes)
|
|
152
|
+
}
|
|
153
|
+
np_consts: NDArrayNumeric = np.zeros(len(node_to_const_idx), dtype=dtype)
|
|
154
|
+
for i, node in enumerate(analysis.const_nodes):
|
|
155
|
+
np_consts[i] = node.value
|
|
156
|
+
|
|
157
|
+
# Where to get input values for each possible node.
|
|
158
|
+
cdef dict[int, ElementID] node_to_element = {}
|
|
159
|
+
# const nodes
|
|
160
|
+
for node_id, const_idx in node_to_const_idx.items():
|
|
161
|
+
node_to_element[node_id] = ElementID(CONSTS, const_idx)
|
|
162
|
+
# var nodes
|
|
163
|
+
for i, var_node in enumerate(analysis.var_nodes):
|
|
164
|
+
if var_node.is_const():
|
|
165
|
+
node_to_element[id(var_node)] = node_to_element[id(var_node.const)]
|
|
166
|
+
else:
|
|
167
|
+
node_to_element[id(var_node)] = ElementID(VARS, i)
|
|
168
|
+
# op nodes
|
|
169
|
+
for node_id, tmp_idx in analysis.op_to_tmp.items():
|
|
170
|
+
node_to_element[node_id] = ElementID(TMPS, tmp_idx)
|
|
171
|
+
for node_id, result_idx in analysis.op_to_result.items():
|
|
172
|
+
node_to_element[node_id] = ElementID(RESULT, result_idx)
|
|
173
|
+
|
|
174
|
+
# Build instructions
|
|
175
|
+
instructions: Instructions = Instructions()
|
|
176
|
+
|
|
177
|
+
cdef object op_node
|
|
178
|
+
for op_node in analysis.op_nodes:
|
|
179
|
+
instructions.append_op(op_node.symbol, op_node, node_to_element)
|
|
180
|
+
|
|
181
|
+
# Add any copy operations, i.e., result nodes that are not op nodes
|
|
182
|
+
for i, node in enumerate(analysis.result_nodes):
|
|
183
|
+
if not isinstance(node, OpNode):
|
|
184
|
+
dest: ElementID = ElementID(RESULT, i)
|
|
185
|
+
src: ElementID = node_to_element[id(node)]
|
|
186
|
+
instructions.append_copy(src, dest)
|
|
187
|
+
|
|
188
|
+
return instructions, np_consts
|
|
189
|
+
|
|
190
|
+
cdef struct ElementID:
|
|
191
|
+
int array # VARS, TMPS, CONSTS, RESULT
|
|
192
|
+
int index # index into the array
|
|
193
|
+
|
|
194
|
+
cdef struct Instruction:
|
|
195
|
+
int symbol # ADD, MUL, COPY
|
|
196
|
+
Py_ssize_t num_args
|
|
197
|
+
ElementID* args
|
|
198
|
+
ElementID dest
|
|
199
|
+
|
|
200
|
+
cdef class Instructions:
|
|
201
|
+
cdef Instruction* instructions
|
|
202
|
+
cdef int allocated
|
|
203
|
+
cdef int num_instructions
|
|
204
|
+
|
|
205
|
+
def __init__(self) -> None:
|
|
206
|
+
self.num_instructions = 0
|
|
207
|
+
self.allocated = 64
|
|
208
|
+
self.instructions = <Instruction *> PyMem_Malloc(self.allocated * sizeof(Instruction))
|
|
209
|
+
|
|
210
|
+
cdef void append_copy(
|
|
211
|
+
self,
|
|
212
|
+
ElementID src,
|
|
213
|
+
ElementID dest,
|
|
214
|
+
) except*:
|
|
215
|
+
c_args = <ElementID *> PyMem_Malloc(sizeof(ElementID))
|
|
216
|
+
if not c_args:
|
|
217
|
+
raise MemoryError()
|
|
218
|
+
|
|
219
|
+
c_args[0] = src
|
|
220
|
+
self._append(COPY, 1, c_args, dest)
|
|
221
|
+
|
|
222
|
+
cdef void append_op(self, int symbol, object op_node: OpNode, dict[int, ElementID] node_to_element) except*:
|
|
223
|
+
args = op_node.args
|
|
224
|
+
cdef Py_ssize_t num_args = len(args)
|
|
225
|
+
|
|
226
|
+
# Create the instruction arguments array
|
|
227
|
+
c_args = <ElementID *> PyMem_Malloc(num_args * sizeof(ElementID))
|
|
228
|
+
if not c_args:
|
|
229
|
+
raise MemoryError()
|
|
230
|
+
|
|
231
|
+
cdef Py_ssize_t i = num_args
|
|
232
|
+
while i > 0:
|
|
233
|
+
i -= 1
|
|
234
|
+
c_args[i] = node_to_element[id(args[i])]
|
|
235
|
+
|
|
236
|
+
dest: ElementID = node_to_element[id(op_node)]
|
|
237
|
+
|
|
238
|
+
self._append(symbol, num_args, c_args, dest)
|
|
239
|
+
|
|
240
|
+
cdef void _append(self, int symbol, Py_ssize_t num_args, ElementID * c_args, ElementID dest) except*:
|
|
241
|
+
cdef int i
|
|
242
|
+
|
|
243
|
+
cdef int num_instructions = self.num_instructions
|
|
244
|
+
|
|
245
|
+
# Ensure sufficient instruction memory
|
|
246
|
+
cdef int allocated = self.allocated
|
|
247
|
+
if num_instructions == allocated:
|
|
248
|
+
allocated *= 2
|
|
249
|
+
self.instructions = <Instruction *> PyMem_Realloc(
|
|
250
|
+
self.instructions,
|
|
251
|
+
allocated * sizeof(Instruction),
|
|
252
|
+
)
|
|
253
|
+
if not self.instructions:
|
|
254
|
+
raise MemoryError()
|
|
255
|
+
self.allocated = allocated
|
|
256
|
+
|
|
257
|
+
# Add the instruction
|
|
258
|
+
self.instructions[num_instructions] = Instruction(
|
|
259
|
+
symbol,
|
|
260
|
+
num_args,
|
|
261
|
+
c_args,
|
|
262
|
+
dest
|
|
263
|
+
)
|
|
264
|
+
self.num_instructions = num_instructions + 1
|
|
265
|
+
|
|
266
|
+
def __dealloc__(self) -> None:
|
|
267
|
+
cdef Instruction * instructions = self.instructions
|
|
268
|
+
if instructions:
|
|
269
|
+
for i in range(self.num_instructions):
|
|
270
|
+
PyMem_Free(instructions[i].args)
|
|
271
|
+
PyMem_Free(instructions)
|
|
272
|
+
|
|
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').
|
|
281
|
+
|
|
282
|
+
cdef int symbol
|
|
283
|
+
cdef cvm_type accumulator
|
|
284
|
+
cdef ElementID * args
|
|
285
|
+
cdef ElementID * args_end
|
|
286
|
+
cdef ElementID * dest
|
|
287
|
+
|
|
288
|
+
# Index the four arrays by constants VARS, TMPS, CONSTS, and RESULT
|
|
289
|
+
cdef (cvm_type *) arrays[4]
|
|
290
|
+
arrays[VARS] = vars_in
|
|
291
|
+
arrays[TMPS] = tmps
|
|
292
|
+
arrays[CONSTS] = consts
|
|
293
|
+
arrays[RESULT] = result
|
|
294
|
+
|
|
295
|
+
cdef Instruction * instruction_ptr = instructions.instructions
|
|
296
|
+
cdef Instruction * instruction_end = instruction_ptr + instructions.num_instructions
|
|
297
|
+
|
|
298
|
+
while instruction_ptr < instruction_end:
|
|
299
|
+
|
|
300
|
+
symbol = instruction_ptr.symbol
|
|
301
|
+
args = instruction_ptr.args
|
|
302
|
+
|
|
303
|
+
accumulator = arrays[args.array][args.index]
|
|
304
|
+
|
|
305
|
+
if symbol == ADD:
|
|
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)
|
|
311
|
+
elif symbol == MUL:
|
|
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)
|
|
317
|
+
# else symbol == COPY, nothing to do
|
|
318
|
+
|
|
319
|
+
dest = &instruction_ptr.dest
|
|
320
|
+
arrays[dest.array][dest.index] = accumulator
|
|
321
|
+
|
|
322
|
+
# Advance the instruction pointer
|
|
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])
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from typing import Optional, Sequence, Tuple
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from ck.circuit import CircuitNode, Circuit, VarNode
|
|
6
|
+
from ck.circuit_compiler.support.input_vars import InferVars, InputVars, infer_input_vars
|
|
7
|
+
from ck.program.raw_program import RawProgram, RawProgramFunction
|
|
8
|
+
from ck.utils.np_extras import DTypeNumeric
|
|
9
|
+
from . import _compiler
|
|
10
|
+
from ..support.circuit_analyser import CircuitAnalysis, analyze_circuit
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def compile_circuit(
|
|
14
|
+
*result: CircuitNode,
|
|
15
|
+
input_vars: InputVars = InferVars.ALL,
|
|
16
|
+
circuit: Optional[Circuit] = None,
|
|
17
|
+
dtype: DTypeNumeric = np.double,
|
|
18
|
+
) -> RawProgram:
|
|
19
|
+
"""
|
|
20
|
+
Make a RawProgram that interprets the given circuit using a Cython virtual cpu.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
*result: if it is a single node, then the resulting function returns a single value,
|
|
24
|
+
if it is a sequence of nodes, then the resulting function returns a numpy array of values.
|
|
25
|
+
input_vars: how to determine the input variables.
|
|
26
|
+
circuit: optionally explicitly specify the Circuit
|
|
27
|
+
dtype: the numpy DType to use for the raw program.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
a raw program.
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
ValueError: if the circuit is unknown, but it is needed.
|
|
34
|
+
ValueError: if not all nodes are from the same circuit.
|
|
35
|
+
ValueError: if the given dtype is not supported.
|
|
36
|
+
"""
|
|
37
|
+
if dtype not in _compiler.DTYPE_TO_CVM_TYPE.keys():
|
|
38
|
+
raise ValueError(f'dtype not supported: {dtype!r}')
|
|
39
|
+
|
|
40
|
+
in_vars: Sequence[VarNode] = infer_input_vars(circuit, result, input_vars)
|
|
41
|
+
return CythonRawProgram(in_vars, result, dtype)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CythonRawProgram(RawProgram):
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
in_vars: Sequence[VarNode],
|
|
48
|
+
result: Sequence[CircuitNode],
|
|
49
|
+
dtype: DTypeNumeric,
|
|
50
|
+
):
|
|
51
|
+
self.in_vars = in_vars
|
|
52
|
+
self.result = result
|
|
53
|
+
|
|
54
|
+
function, number_of_tmps = _make_function(
|
|
55
|
+
var_nodes=in_vars,
|
|
56
|
+
result_nodes=result,
|
|
57
|
+
dtype=dtype,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
super().__init__(
|
|
61
|
+
function=function,
|
|
62
|
+
dtype=dtype,
|
|
63
|
+
number_of_vars=len(in_vars),
|
|
64
|
+
number_of_tmps=number_of_tmps,
|
|
65
|
+
number_of_results=len(result),
|
|
66
|
+
var_indices=tuple(var.idx for var in in_vars),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def __getstate__(self):
|
|
70
|
+
"""
|
|
71
|
+
Support for pickle.
|
|
72
|
+
"""
|
|
73
|
+
return {
|
|
74
|
+
'dtype': self.dtype,
|
|
75
|
+
'number_of_vars': self.number_of_vars,
|
|
76
|
+
'number_of_tmps': self.number_of_tmps,
|
|
77
|
+
'number_of_results': self.number_of_results,
|
|
78
|
+
'var_indices': self.var_indices,
|
|
79
|
+
#
|
|
80
|
+
'in_vars': self.in_vars,
|
|
81
|
+
'result': self.result,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
def __setstate__(self, state):
|
|
85
|
+
"""
|
|
86
|
+
Support for pickle.
|
|
87
|
+
"""
|
|
88
|
+
self.dtype = state['dtype']
|
|
89
|
+
self.number_of_vars = state['number_of_vars']
|
|
90
|
+
self.number_of_tmps = state['number_of_tmps']
|
|
91
|
+
self.number_of_results = state['number_of_results']
|
|
92
|
+
self.var_indices = state['var_indices']
|
|
93
|
+
#
|
|
94
|
+
self.in_vars = state['in_vars']
|
|
95
|
+
self.result = state['result']
|
|
96
|
+
|
|
97
|
+
self.function, _ = _make_function(
|
|
98
|
+
var_nodes=self.in_vars,
|
|
99
|
+
result_nodes=self.result,
|
|
100
|
+
dtype=self.dtype,
|
|
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)
|