compiled-knowledge 4.0.0a5__cp313-cp313-macosx_10_13_universal2.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 +13 -0
- ck/circuit/circuit.c +38749 -0
- ck/circuit/circuit.cpython-313-darwin.so +0 -0
- ck/circuit/circuit_py.py +807 -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 +17373 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.cpython-313-darwin.so +0 -0
- ck/circuit_compiler/cython_vm_compiler/cython_vm_compiler.py +96 -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.py +81 -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 +53674 -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 +288 -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 +3494 -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 +75 -0
- ck/pgm_circuit/program_with_slotmap.py +234 -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 +252 -0
- ck/pgm_compiler/factor_elimination.py +383 -0
- ck/pgm_compiler/named_pgm_compilers.py +63 -0
- ck/pgm_compiler/pgm_compiler.py +19 -0
- ck/pgm_compiler/recursive_conditioning.py +226 -0
- ck/pgm_compiler/support/__init__.py +0 -0
- ck/pgm_compiler/support/circuit_table/__init__.py +9 -0
- ck/pgm_compiler/support/circuit_table/circuit_table.c +16042 -0
- ck/pgm_compiler/support/circuit_table/circuit_table.cpython-313-darwin.so +0 -0
- ck/pgm_compiler/support/circuit_table/circuit_table_py.py +269 -0
- ck/pgm_compiler/support/clusters.py +556 -0
- ck/pgm_compiler/support/factor_tables.py +398 -0
- ck/pgm_compiler/support/join_tree.py +275 -0
- ck/pgm_compiler/support/named_compiler_maker.py +33 -0
- ck/pgm_compiler/variable_elimination.py +89 -0
- ck/probability/__init__.py +0 -0
- ck/probability/empirical_probability_space.py +47 -0
- ck/probability/probability_space.py +568 -0
- ck/program/__init__.py +3 -0
- ck/program/program.py +129 -0
- ck/program/program_buffer.py +180 -0
- ck/program/raw_program.py +61 -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 +66 -0
- ck/sampling/wmc_direct_sampler.py +169 -0
- ck/sampling/wmc_gibbs_sampler.py +147 -0
- ck/sampling/wmc_metropolis_sampler.py +159 -0
- ck/sampling/wmc_rejection_sampler.py +113 -0
- ck/utils/__init__.py +0 -0
- ck/utils/iter_extras.py +153 -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 +44 -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 +50 -0
- ck_demos/pgm_compiler/demo_compiler_dump.py +50 -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_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 +88 -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.0a5.dist-info/METADATA +50 -0
- compiled_knowledge-4.0.0a5.dist-info/RECORD +167 -0
- compiled_knowledge-4.0.0a5.dist-info/WHEEL +5 -0
- compiled_knowledge-4.0.0a5.dist-info/licenses/LICENSE.txt +21 -0
- compiled_knowledge-4.0.0a5.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Sequence, Tuple, Dict, Iterable, Set, Iterator
|
|
4
|
+
|
|
5
|
+
from ck.circuit import CircuitNode, Circuit
|
|
6
|
+
from ck.utils.map_list import MapList
|
|
7
|
+
|
|
8
|
+
TableInstance = Tuple[int, ...]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CircuitTable:
|
|
12
|
+
"""
|
|
13
|
+
A circuit table manages a set of CircuitNodes, where each node corresponds
|
|
14
|
+
to an instance for a set of (zero or more) random variables.
|
|
15
|
+
|
|
16
|
+
Operations on circuit tables typically add circuit nodes to the circuit. It will
|
|
17
|
+
heuristically avoid adding unnecessary nodes (e.g. addition of zero, multiplication
|
|
18
|
+
by zero or one.) However, it may be that interim circuit nodes are created that
|
|
19
|
+
end up not being used. Consider calling `Circuit.remove_unreachable_op_nodes` after
|
|
20
|
+
completing all circuit table operations.
|
|
21
|
+
|
|
22
|
+
It is generally expected that no CircuitTable row will be created with a constant
|
|
23
|
+
zero node. These are assumed to be optimised out already.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
circuit: Circuit,
|
|
29
|
+
rv_idxs: Sequence[int],
|
|
30
|
+
rows: Iterable[Tuple[TableInstance, CircuitNode]] = (),
|
|
31
|
+
):
|
|
32
|
+
"""
|
|
33
|
+
Args:
|
|
34
|
+
circuit: the circuit whose nodes are being managed by this table.
|
|
35
|
+
rv_idxs: indexes of random variables.
|
|
36
|
+
rows: optional rows to add to the table.
|
|
37
|
+
|
|
38
|
+
Assumes:
|
|
39
|
+
* rv_idxs contains no duplicates.
|
|
40
|
+
* all row instances conform to the indexed random variables.
|
|
41
|
+
* all row circuit nodes belong to the given circuit.
|
|
42
|
+
"""
|
|
43
|
+
self.circuit: Circuit = circuit
|
|
44
|
+
self.rv_idxs: Tuple[int, ...] = tuple(rv_idxs)
|
|
45
|
+
self.rows: Dict[TableInstance, CircuitNode] = dict(rows)
|
|
46
|
+
|
|
47
|
+
def __len__(self) -> int:
|
|
48
|
+
return len(self.rows)
|
|
49
|
+
|
|
50
|
+
def get(self, key, default=None):
|
|
51
|
+
return self.rows.get(key, default)
|
|
52
|
+
|
|
53
|
+
def __getitem__(self, key):
|
|
54
|
+
return self.rows[key]
|
|
55
|
+
|
|
56
|
+
def __setitem__(self, key, value):
|
|
57
|
+
self.rows[key] = value
|
|
58
|
+
|
|
59
|
+
def top(self) -> CircuitNode:
|
|
60
|
+
"""
|
|
61
|
+
Get the circuit top value.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
RuntimeError if there is more than one row in the table.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
A single circuit node.
|
|
68
|
+
"""
|
|
69
|
+
if len(self.rows) == 0:
|
|
70
|
+
return self.circuit.zero
|
|
71
|
+
elif len(self.rows) == 1:
|
|
72
|
+
return next(iter(self.rows.values()))
|
|
73
|
+
else:
|
|
74
|
+
raise RuntimeError('cannot get top node from a table with more that 1 row')
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# ==================================================================================
|
|
78
|
+
# Circuit Table Operations
|
|
79
|
+
# ==================================================================================
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def sum_out(table: CircuitTable, rv_idxs: Iterable[int]) -> CircuitTable:
|
|
83
|
+
"""
|
|
84
|
+
Return a circuit table that results from summing out
|
|
85
|
+
the given random variables of this circuit table.
|
|
86
|
+
|
|
87
|
+
Normally this will return a new table. However, if rv_idxs is empty,
|
|
88
|
+
then the given table is returned unmodified.
|
|
89
|
+
|
|
90
|
+
Raises:
|
|
91
|
+
ValueError if rv_idxs is not a subset of table.rv_idxs.
|
|
92
|
+
ValueError if rv_idxs contains duplicates.
|
|
93
|
+
"""
|
|
94
|
+
rv_idxs: Sequence[int] = tuple(rv_idxs)
|
|
95
|
+
|
|
96
|
+
if len(rv_idxs) == 0:
|
|
97
|
+
# nothing to do
|
|
98
|
+
return table
|
|
99
|
+
|
|
100
|
+
rv_idxs_set: Set[int] = set(rv_idxs)
|
|
101
|
+
if len(rv_idxs_set) != len(rv_idxs):
|
|
102
|
+
raise ValueError('rv_idxs contains duplicates')
|
|
103
|
+
if not rv_idxs_set.issubset(table.rv_idxs):
|
|
104
|
+
raise ValueError('rv_idxs is not a subset of table.rv_idxs')
|
|
105
|
+
|
|
106
|
+
remaining_rv_idxs = tuple(
|
|
107
|
+
rv_index
|
|
108
|
+
for rv_index in table.rv_idxs
|
|
109
|
+
if rv_index not in rv_idxs_set
|
|
110
|
+
)
|
|
111
|
+
num_remaining = len(remaining_rv_idxs)
|
|
112
|
+
if num_remaining == 0:
|
|
113
|
+
# Special case: summing out all random variables
|
|
114
|
+
return sum_out_all(table)
|
|
115
|
+
|
|
116
|
+
# index_map[i] is the location in table.rv_idxs for remaining_rv_idxs[i]
|
|
117
|
+
index_map = tuple(
|
|
118
|
+
table.rv_idxs.index(remaining_rv_index)
|
|
119
|
+
for remaining_rv_index in remaining_rv_idxs
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
groups: MapList[TableInstance, CircuitNode] = MapList()
|
|
123
|
+
for instance, node in table.rows.items():
|
|
124
|
+
group_instance = tuple(instance[i] for i in index_map)
|
|
125
|
+
groups.append(group_instance, node)
|
|
126
|
+
|
|
127
|
+
circuit: Circuit = table.circuit
|
|
128
|
+
|
|
129
|
+
def _result_rows() -> Iterator[Tuple[TableInstance, CircuitNode]]:
|
|
130
|
+
for group, to_add in groups.items():
|
|
131
|
+
_node: CircuitNode = circuit.optimised_add(to_add)
|
|
132
|
+
if not _node.is_zero():
|
|
133
|
+
yield group, _node
|
|
134
|
+
|
|
135
|
+
return CircuitTable(circuit, remaining_rv_idxs, _result_rows())
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def sum_out_all(table: CircuitTable) -> CircuitTable:
|
|
139
|
+
"""
|
|
140
|
+
Return a circuit table that results from summing out
|
|
141
|
+
all random variables of this circuit table.
|
|
142
|
+
"""
|
|
143
|
+
circuit: Circuit = table.circuit
|
|
144
|
+
num_rows: int = len(table)
|
|
145
|
+
if num_rows == 0:
|
|
146
|
+
return CircuitTable(circuit, ())
|
|
147
|
+
elif num_rows == 1:
|
|
148
|
+
node = next(iter(table.rows.values()))
|
|
149
|
+
else:
|
|
150
|
+
node: CircuitNode = circuit.optimised_add(table.rows.values())
|
|
151
|
+
if node.is_zero():
|
|
152
|
+
return CircuitTable(circuit, ())
|
|
153
|
+
|
|
154
|
+
return CircuitTable(circuit, (), [((), node)])
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def project(table: CircuitTable, rv_idxs: Iterable[int]) -> CircuitTable:
|
|
158
|
+
"""
|
|
159
|
+
Call `sum_out(table, to_sum_out)`, where
|
|
160
|
+
`to_sum_out = table.rv_idxs - rv_idxs`.
|
|
161
|
+
"""
|
|
162
|
+
to_sum_out: Set[int] = set(table.rv_idxs)
|
|
163
|
+
to_sum_out.difference_update(rv_idxs)
|
|
164
|
+
return sum_out(table, to_sum_out)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def product(x: CircuitTable, y: CircuitTable) -> CircuitTable:
|
|
168
|
+
"""
|
|
169
|
+
Return a circuit table that results from the product of the two given tables.
|
|
170
|
+
|
|
171
|
+
If x or y equals `one_table`, then the other table is returned. Otherwise,
|
|
172
|
+
a new circuit table will be constructed and returned.
|
|
173
|
+
"""
|
|
174
|
+
circuit: Circuit = x.circuit
|
|
175
|
+
if y.circuit is not circuit:
|
|
176
|
+
raise ValueError('circuit tables must refer to the same circuit')
|
|
177
|
+
|
|
178
|
+
# Make the smaller table 'y', and the other 'x'.
|
|
179
|
+
# This is to minimise the index size on 'y'.
|
|
180
|
+
if len(x) < len(y):
|
|
181
|
+
x, y = y, x
|
|
182
|
+
|
|
183
|
+
x_rv_idxs: Tuple[int, ...] = x.rv_idxs
|
|
184
|
+
y_rv_idxs: Tuple[int, ...] = y.rv_idxs
|
|
185
|
+
|
|
186
|
+
# Special case: y == 0 or 1, and has no random variables.
|
|
187
|
+
if y_rv_idxs == ():
|
|
188
|
+
if len(y) == 1 and y.top().is_one():
|
|
189
|
+
return x
|
|
190
|
+
elif len(y) == 0:
|
|
191
|
+
return CircuitTable(circuit, x_rv_idxs)
|
|
192
|
+
|
|
193
|
+
# Set operations on rv indexes. After these operations:
|
|
194
|
+
# * co_rv_idxs is the set of rv indexes common (co) to x and y,
|
|
195
|
+
# * yo_rv_idxs is the set of rv indexes in y only (yo), and not in x.
|
|
196
|
+
yo_rv_idxs: Set[int] = set(y_rv_idxs)
|
|
197
|
+
co_rv_idxs: Set[int] = set(x_rv_idxs)
|
|
198
|
+
co_rv_idxs.intersection_update(yo_rv_idxs)
|
|
199
|
+
yo_rv_idxs.difference_update(co_rv_idxs)
|
|
200
|
+
|
|
201
|
+
if len(co_rv_idxs) == 0:
|
|
202
|
+
# Special case: no common random variables.
|
|
203
|
+
return _product_no_common_rvs(x, y)
|
|
204
|
+
|
|
205
|
+
# Convert random variable index sets to sequences
|
|
206
|
+
yo_rv_idxs: Tuple[int, ...] = tuple(yo_rv_idxs) # y only random variables
|
|
207
|
+
co_rv_idxs: Tuple[int, ...] = tuple(co_rv_idxs) # common random variables
|
|
208
|
+
|
|
209
|
+
# Cache mappings from result Instance to index into source Instance (x or y).
|
|
210
|
+
# This will be used in indexing and product loops to pull our needed values
|
|
211
|
+
# from the source instances.
|
|
212
|
+
co_from_x_map = tuple(x.rv_idxs.index(rv_index) for rv_index in co_rv_idxs)
|
|
213
|
+
co_from_y_map = tuple(y.rv_idxs.index(rv_index) for rv_index in co_rv_idxs)
|
|
214
|
+
yo_from_y_map = tuple(y.rv_idxs.index(rv_index) for rv_index in yo_rv_idxs)
|
|
215
|
+
|
|
216
|
+
# Index the y rows by common-only key (y is the smaller of the two tables).
|
|
217
|
+
y_index: MapList[TableInstance, Tuple[TableInstance, CircuitNode]] = MapList()
|
|
218
|
+
for y_instance, y_node in y.rows.items():
|
|
219
|
+
co = tuple(y_instance[i] for i in co_from_y_map)
|
|
220
|
+
yo = tuple(y_instance[i] for i in yo_from_y_map)
|
|
221
|
+
y_index.append(co, (yo, y_node))
|
|
222
|
+
|
|
223
|
+
def _result_rows() -> Iterator[Tuple[TableInstance, CircuitNode]]:
|
|
224
|
+
# Iterate over x rows, yielding (instance, value).
|
|
225
|
+
# Rows with constant node values of one are optimised out.
|
|
226
|
+
for _x_instance, _x_node in x.rows.items():
|
|
227
|
+
_co = tuple(_x_instance[i] for i in co_from_x_map)
|
|
228
|
+
if _x_node.is_one():
|
|
229
|
+
# Multiplying by one.
|
|
230
|
+
# Iterate over matching y rows.
|
|
231
|
+
for _yo, _y_node in y_index.get(_co, ()):
|
|
232
|
+
yield _x_instance + _yo, _y_node
|
|
233
|
+
else:
|
|
234
|
+
# Iterate over matching y rows.
|
|
235
|
+
for _yo, _y_node in y_index.get(_co, ()):
|
|
236
|
+
yield _x_instance + _yo, circuit.optimised_mul((_x_node, _y_node))
|
|
237
|
+
|
|
238
|
+
return CircuitTable(circuit, x_rv_idxs + yo_rv_idxs, _result_rows())
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _product_no_common_rvs(x: CircuitTable, y: CircuitTable) -> CircuitTable:
|
|
242
|
+
"""
|
|
243
|
+
Return the product of x and y, where x and y have no common random variables.
|
|
244
|
+
|
|
245
|
+
This is an optimisation of more general product algorithm as no index needs
|
|
246
|
+
to be construction based on the common random variables.
|
|
247
|
+
|
|
248
|
+
Rows with constant node values of one are optimised out.
|
|
249
|
+
|
|
250
|
+
Assumes:
|
|
251
|
+
* There are no common random variables between x and y.
|
|
252
|
+
* x and y are for the same circuit.
|
|
253
|
+
"""
|
|
254
|
+
circuit: Circuit = x.circuit
|
|
255
|
+
|
|
256
|
+
result_rv_idxs: Tuple[int, ...] = x.rv_idxs + y.rv_idxs
|
|
257
|
+
|
|
258
|
+
def _result_rows() -> Iterator[Tuple[TableInstance, CircuitNode]]:
|
|
259
|
+
for x_instance, x_node in x.rows.items():
|
|
260
|
+
if x_node.is_one():
|
|
261
|
+
for y_instance, y_node in y.rows.items():
|
|
262
|
+
instance = x_instance + y_instance
|
|
263
|
+
yield instance, y_node
|
|
264
|
+
else:
|
|
265
|
+
for y_instance, y_node in y.rows.items():
|
|
266
|
+
instance = x_instance + y_instance
|
|
267
|
+
yield instance, circuit.optimised_mul((x_node, y_node))
|
|
268
|
+
|
|
269
|
+
return CircuitTable(circuit, result_rv_idxs, _result_rows())
|