compiled-knowledge 4.0.0a15__cp312-cp312-win_amd64.whl → 4.0.0a17__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 +2 -2
- ck/circuit/_circuit_cy.cp312-win_amd64.pyd +0 -0
- ck/circuit/{circuit.pyx → _circuit_cy.pyx} +65 -57
- ck/circuit/{circuit_py.py → _circuit_py.py} +14 -6
- ck/circuit_compiler/cython_vm_compiler/_compiler.c +1603 -2030
- ck/circuit_compiler/cython_vm_compiler/_compiler.cp312-win_amd64.pyd +0 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.pyx +85 -58
- ck/circuit_compiler/named_circuit_compilers.py +1 -1
- ck/in_out/parse_ace_nnf.py +71 -47
- ck/in_out/parser_utils.py +1 -1
- ck/pgm_compiler/ace/ace.py +8 -2
- ck/pgm_compiler/factor_elimination.py +23 -13
- ck/pgm_compiler/support/circuit_table/__init__.py +2 -2
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy.cp312-win_amd64.pyd +0 -0
- ck/pgm_compiler/support/circuit_table/{circuit_table.pyx → _circuit_table_cy.pyx} +9 -9
- ck/pgm_compiler/support/circuit_table/{circuit_table_py.py → _circuit_table_py.py} +5 -5
- ck/pgm_compiler/support/clusters.py +16 -4
- ck/pgm_compiler/support/factor_tables.py +1 -1
- ck/pgm_compiler/support/join_tree.py +67 -10
- ck/pgm_compiler/variable_elimination.py +2 -0
- ck/utils/local_config.py +270 -0
- ck_demos/pgm_compiler/compare_pgm_compilers.py +2 -0
- ck_demos/pgm_compiler/demo_compiler_dump.py +10 -0
- ck_demos/pgm_compiler/time_fe_compiler.py +93 -0
- ck_demos/utils/compare.py +30 -20
- {compiled_knowledge-4.0.0a15.dist-info → compiled_knowledge-4.0.0a17.dist-info}/METADATA +1 -1
- {compiled_knowledge-4.0.0a15.dist-info → compiled_knowledge-4.0.0a17.dist-info}/RECORD +30 -31
- ck/circuit/circuit.c +0 -38861
- ck/circuit/circuit.cp312-win_amd64.pyd +0 -0
- ck/circuit/circuit_node.pyx +0 -138
- ck/pgm_compiler/support/circuit_table/circuit_table.c +0 -16042
- ck/pgm_compiler/support/circuit_table/circuit_table.cp312-win_amd64.pyd +0 -0
- {compiled_knowledge-4.0.0a15.dist-info → compiled_knowledge-4.0.0a17.dist-info}/WHEEL +0 -0
- {compiled_knowledge-4.0.0a15.dist-info → compiled_knowledge-4.0.0a17.dist-info}/licenses/LICENSE.txt +0 -0
- {compiled_knowledge-4.0.0a15.dist-info → compiled_knowledge-4.0.0a17.dist-info}/top_level.txt +0 -0
ck/circuit/__init__.py
CHANGED
|
Binary file
|
|
@@ -4,7 +4,7 @@ For more documentation on this module, refer to the Jupyter notebook docs/6_circ
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
from itertools import chain
|
|
7
|
-
from typing import Dict, Tuple, Optional, Iterable, Sequence, List, overload,
|
|
7
|
+
from typing import Dict, Tuple, Optional, Iterable, Sequence, List, overload, Any
|
|
8
8
|
|
|
9
9
|
# Type for values of ConstNode objects
|
|
10
10
|
ConstValue = float | int | bool
|
|
@@ -48,8 +48,11 @@ cdef class Circuit:
|
|
|
48
48
|
self.ops: List[OpNode] = []
|
|
49
49
|
self._const_map: Dict[ConstValue, ConstNode] = {}
|
|
50
50
|
self.__derivatives: Optional[_DerivativeHelper] = None # cache for partial derivatives calculations.
|
|
51
|
-
self.zero: ConstNode = self
|
|
52
|
-
self.one: ConstNode = self
|
|
51
|
+
self.zero: ConstNode = ConstNode(self, zero, is_zero=True)
|
|
52
|
+
self.one: ConstNode = ConstNode(self, one, is_one=True)
|
|
53
|
+
|
|
54
|
+
self._const_map[zero] = self.zero
|
|
55
|
+
self._const_map[one] = self.one
|
|
53
56
|
|
|
54
57
|
@property
|
|
55
58
|
def number_of_vars(self) -> int:
|
|
@@ -124,8 +127,8 @@ cdef class Circuit:
|
|
|
124
127
|
self._const_map[value] = node
|
|
125
128
|
return node
|
|
126
129
|
|
|
127
|
-
cdef
|
|
128
|
-
cdef
|
|
130
|
+
cdef OpNode _op(self, int symbol, tuple[CircuitNode, ...] nodes):
|
|
131
|
+
cdef OpNode node = OpNode(self, symbol, nodes)
|
|
129
132
|
self.ops.append(node)
|
|
130
133
|
return node
|
|
131
134
|
|
|
@@ -133,14 +136,14 @@ cdef class Circuit:
|
|
|
133
136
|
"""
|
|
134
137
|
Create and return a new 'addition' node, applied to the given arguments.
|
|
135
138
|
"""
|
|
136
|
-
cdef list[
|
|
139
|
+
cdef list[CircuitNode] args = self._check_nodes(nodes)
|
|
137
140
|
return self._op(ADD, tuple(args))
|
|
138
141
|
|
|
139
142
|
def mul(self, *nodes: Args) -> OpNode:
|
|
140
143
|
"""
|
|
141
144
|
Create and return a new 'multiplication' node, applied to the given arguments.
|
|
142
145
|
"""
|
|
143
|
-
cdef list[
|
|
146
|
+
cdef list[CircuitNode] args = self._check_nodes(nodes)
|
|
144
147
|
return self._op(MUL, tuple(args))
|
|
145
148
|
|
|
146
149
|
cpdef object optimised_add(self, object nodes: Iterable[CircuitNode]): # -> CircuitNode:
|
|
@@ -151,12 +154,12 @@ cdef class Circuit:
|
|
|
151
154
|
# * singleton addition is avoided: add(x) = x,
|
|
152
155
|
# * empty addition is avoided: add() = 0.
|
|
153
156
|
|
|
154
|
-
cdef list[
|
|
155
|
-
cdef
|
|
157
|
+
cdef list[CircuitNode] to_add = []
|
|
158
|
+
cdef CircuitNode n
|
|
156
159
|
for n in nodes:
|
|
157
160
|
if n.circuit is not self:
|
|
158
161
|
raise RuntimeError('node does not belong to this circuit')
|
|
159
|
-
if not n.is_zero
|
|
162
|
+
if not n.is_zero:
|
|
160
163
|
to_add.append(n)
|
|
161
164
|
cdef int len_to_add = len(to_add)
|
|
162
165
|
if len_to_add == 0:
|
|
@@ -174,14 +177,14 @@ cdef class Circuit:
|
|
|
174
177
|
# * multiplication by one is avoided: mul(x, 1) = x,
|
|
175
178
|
# * singleton multiplication is avoided: mul(x) = x,
|
|
176
179
|
# * empty multiplication is avoided: mul() = 1.
|
|
177
|
-
cdef list[
|
|
178
|
-
cdef
|
|
180
|
+
cdef list[CircuitNode] to_mul = []
|
|
181
|
+
cdef CircuitNode n
|
|
179
182
|
for n in nodes:
|
|
180
183
|
if n.circuit is not self:
|
|
181
184
|
raise RuntimeError('node does not belong to this circuit')
|
|
182
|
-
if n.is_zero
|
|
185
|
+
if n.is_zero:
|
|
183
186
|
return self.zero
|
|
184
|
-
if not n.is_one
|
|
187
|
+
if not n.is_one:
|
|
185
188
|
to_mul.append(n)
|
|
186
189
|
cdef int len_to_mul = len(to_mul)
|
|
187
190
|
if len_to_mul == 0:
|
|
@@ -300,8 +303,15 @@ cdef class Circuit:
|
|
|
300
303
|
Args:
|
|
301
304
|
*nodes: may be either a node or a list of nodes.
|
|
302
305
|
"""
|
|
303
|
-
|
|
304
|
-
|
|
306
|
+
nodes = self._check_nodes(nodes)
|
|
307
|
+
self._remove_unreachable_op_nodes(nodes)
|
|
308
|
+
|
|
309
|
+
cdef void _remove_unreachable_op_nodes(self, list[CircuitNode] nodes):
|
|
310
|
+
# Set of object ids for all reachable op nodes
|
|
311
|
+
cdef set[int] seen = set()
|
|
312
|
+
|
|
313
|
+
cdef CircuitNode node
|
|
314
|
+
for node in nodes:
|
|
305
315
|
_reachable_op_nodes_seen_r(node, seen)
|
|
306
316
|
|
|
307
317
|
if len(seen) < len(self.ops):
|
|
@@ -328,9 +338,17 @@ cdef class Circuit:
|
|
|
328
338
|
Returned nodes are not repeated.
|
|
329
339
|
The result is ordered such that if result[i] is referenced by result[j] then i < j.
|
|
330
340
|
"""
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
341
|
+
nodes = self._check_nodes(nodes)
|
|
342
|
+
return self._reachable_op_nodes(nodes)
|
|
343
|
+
|
|
344
|
+
cdef list[OpNode] _reachable_op_nodes(self, list[CircuitNode] nodes):
|
|
345
|
+
# Set of object ids for all reachable op nodes
|
|
346
|
+
cdef set[int] seen = set()
|
|
347
|
+
|
|
348
|
+
cdef list[OpNode] result = []
|
|
349
|
+
|
|
350
|
+
cdef CircuitNode node
|
|
351
|
+
for node in nodes:
|
|
334
352
|
_reachable_op_nodes_r(node, seen, result)
|
|
335
353
|
return result
|
|
336
354
|
|
|
@@ -397,7 +415,7 @@ cdef class Circuit:
|
|
|
397
415
|
args_str = ' '.join(node_name[id(arg)] for arg in op.args)
|
|
398
416
|
print(f'{next_prefix}{op_name}: {args_str}')
|
|
399
417
|
|
|
400
|
-
cdef list[
|
|
418
|
+
cdef list[CircuitNode] _check_nodes(self, object nodes: Iterable[Args]): # -> Sequence[CircuitNode]:
|
|
401
419
|
# Convert the given circuit nodes to a tuple, flattening nested iterables as needed.
|
|
402
420
|
#
|
|
403
421
|
# Args:
|
|
@@ -405,11 +423,11 @@ cdef class Circuit:
|
|
|
405
423
|
#
|
|
406
424
|
# Raises:
|
|
407
425
|
# RuntimeError: if any node does not belong to this circuit.
|
|
408
|
-
cdef list[
|
|
426
|
+
cdef list[CircuitNode] result = []
|
|
409
427
|
self.__check_nodes(nodes, result)
|
|
410
428
|
return result
|
|
411
429
|
|
|
412
|
-
cdef __check_nodes(self, nodes: Iterable[Args], list[
|
|
430
|
+
cdef void __check_nodes(self, nodes: Iterable[Args], list[CircuitNode] result):
|
|
413
431
|
# Convert the given circuit nodes to a tuple, flattening nested iterables as needed.
|
|
414
432
|
#
|
|
415
433
|
# Args:
|
|
@@ -428,7 +446,7 @@ cdef class Circuit:
|
|
|
428
446
|
else:
|
|
429
447
|
self.__check_nodes(node, result)
|
|
430
448
|
|
|
431
|
-
cdef object _derivatives(self,
|
|
449
|
+
cdef object _derivatives(self, CircuitNode f):
|
|
432
450
|
# Get a _DerivativeHelper for `f`.
|
|
433
451
|
# Checking the derivative cache.
|
|
434
452
|
derivatives: Optional[_DerivativeHelper] = self.__derivatives
|
|
@@ -452,16 +470,14 @@ cdef class CircuitNode:
|
|
|
452
470
|
A var node may be temporarily set to be a constant node, which may
|
|
453
471
|
be useful for optimising a compiled circuit.
|
|
454
472
|
"""
|
|
455
|
-
cdef public
|
|
473
|
+
cdef public Circuit circuit
|
|
474
|
+
cdef public bint is_zero
|
|
475
|
+
cdef public bint is_one
|
|
456
476
|
|
|
457
|
-
def __init__(self, circuit):
|
|
477
|
+
def __init__(self, circuit: Circuit, is_zero: bool, is_one: bool):
|
|
458
478
|
self.circuit = circuit
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
return False
|
|
462
|
-
|
|
463
|
-
cpdef int is_one(self) except*:
|
|
464
|
-
return False
|
|
479
|
+
self.is_zero = is_zero
|
|
480
|
+
self.is_one = is_one
|
|
465
481
|
|
|
466
482
|
def __add__(self, other: CircuitNode | ConstValue):
|
|
467
483
|
return self.circuit.add(self, other)
|
|
@@ -471,23 +487,14 @@ cdef class CircuitNode:
|
|
|
471
487
|
|
|
472
488
|
|
|
473
489
|
cdef class ConstNode(CircuitNode):
|
|
490
|
+
# A node in a circuit representing a constant value.
|
|
491
|
+
|
|
474
492
|
cdef public object value
|
|
475
493
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
"""
|
|
479
|
-
def __init__(self, circuit, value: ConstValue):
|
|
480
|
-
super().__init__(circuit)
|
|
494
|
+
def __init__(self, circuit, value: ConstValue, is_zero: bool = False, is_one: bool = False):
|
|
495
|
+
super().__init__(circuit, is_zero, is_one)
|
|
481
496
|
self.value: ConstValue = value
|
|
482
497
|
|
|
483
|
-
cpdef int is_zero(self) except*:
|
|
484
|
-
# noinspection PyProtectedMember
|
|
485
|
-
return self is self.circuit.zero
|
|
486
|
-
|
|
487
|
-
cpdef int is_one(self) except*:
|
|
488
|
-
# noinspection PyProtectedMember
|
|
489
|
-
return self is self.circuit.one
|
|
490
|
-
|
|
491
498
|
def __str__(self) -> str:
|
|
492
499
|
return 'const(' + str(self.value) + ')'
|
|
493
500
|
|
|
@@ -506,16 +513,10 @@ cdef class VarNode(CircuitNode):
|
|
|
506
513
|
cdef object _const
|
|
507
514
|
|
|
508
515
|
def __init__(self, circuit, idx: int):
|
|
509
|
-
super().__init__(circuit)
|
|
516
|
+
super().__init__(circuit, False, False)
|
|
510
517
|
self.idx = idx
|
|
511
518
|
self._const = None
|
|
512
519
|
|
|
513
|
-
cpdef int is_zero(self) except*:
|
|
514
|
-
return self._const is not None and self._const.is_zero()
|
|
515
|
-
|
|
516
|
-
cpdef int is_one(self) except*:
|
|
517
|
-
return self._const is not None and self._const.is_one()
|
|
518
|
-
|
|
519
520
|
cpdef int is_const(self) except*:
|
|
520
521
|
return self._const is not None
|
|
521
522
|
|
|
@@ -527,8 +528,13 @@ cdef class VarNode(CircuitNode):
|
|
|
527
528
|
def const(self, value: ConstValue | ConstNode | None) -> None:
|
|
528
529
|
if value is None:
|
|
529
530
|
self._const = None
|
|
531
|
+
self.is_zero = False
|
|
532
|
+
self.is_one = False
|
|
530
533
|
else:
|
|
531
|
-
|
|
534
|
+
const_node: ConstNode = self.circuit.const(value)
|
|
535
|
+
self._const = const_node
|
|
536
|
+
self.is_zero = const_node.is_zero
|
|
537
|
+
self.is_one = const_node.is_one
|
|
532
538
|
|
|
533
539
|
def __lt__(self, other) -> bool:
|
|
534
540
|
if isinstance(other, VarNode):
|
|
@@ -550,7 +556,7 @@ cdef class OpNode(CircuitNode):
|
|
|
550
556
|
cdef public int symbol
|
|
551
557
|
|
|
552
558
|
def __init__(self, object circuit, symbol: int, tuple[object, ...] args: Tuple[CircuitNode]):
|
|
553
|
-
super().__init__(circuit)
|
|
559
|
+
super().__init__(circuit, False, False)
|
|
554
560
|
self.args = tuple(args)
|
|
555
561
|
self.symbol = int(symbol)
|
|
556
562
|
|
|
@@ -673,7 +679,7 @@ class _DerivativeHelper:
|
|
|
673
679
|
to_add: Sequence[CircuitNode] = tuple(
|
|
674
680
|
value
|
|
675
681
|
for value in (self._derivative_prod(prods) for prods in d_node.sum_prod)
|
|
676
|
-
if not value.is_zero
|
|
682
|
+
if not value.is_zero
|
|
677
683
|
)
|
|
678
684
|
# we can release the temporary memory at this DNode now
|
|
679
685
|
d_node.sum_prod = None
|
|
@@ -748,6 +754,8 @@ class _DerivativeHelper:
|
|
|
748
754
|
|
|
749
755
|
def _get(self, node: CircuitNode) -> _DNode:
|
|
750
756
|
"""
|
|
757
|
+
Helper for derivatives.
|
|
758
|
+
|
|
751
759
|
Get the DNode for the given circuit node.
|
|
752
760
|
If no DNode exist for it yet, then one will be constructed.
|
|
753
761
|
"""
|
|
@@ -759,13 +767,13 @@ class _DerivativeHelper:
|
|
|
759
767
|
return d_node
|
|
760
768
|
|
|
761
769
|
|
|
762
|
-
cdef void _reachable_op_nodes_r(
|
|
770
|
+
cdef void _reachable_op_nodes_r(CircuitNode node, set[int] seen, list[OpNode] result):
|
|
763
771
|
# Recursive helper for `reachable_op_nodes`. Performs a depth-first search.
|
|
764
772
|
#
|
|
765
773
|
# Args:
|
|
766
774
|
# node: the current node being checked.
|
|
767
775
|
# seen: keep track of seen op node ids (to avoid returning multiple of the same node).
|
|
768
|
-
# result: a list where the nodes are added
|
|
776
|
+
# result: a list where the seen nodes are added.
|
|
769
777
|
if isinstance(node, OpNode) and id(node) not in seen:
|
|
770
778
|
seen.add(id(node))
|
|
771
779
|
for arg in node.args:
|
|
@@ -773,7 +781,7 @@ cdef void _reachable_op_nodes_r(object node: CircuitNode, set seen: Set[int], li
|
|
|
773
781
|
result.append(node)
|
|
774
782
|
|
|
775
783
|
|
|
776
|
-
cdef void _reachable_op_nodes_seen_r(
|
|
784
|
+
cdef void _reachable_op_nodes_seen_r(CircuitNode node, set[int] seen):
|
|
777
785
|
# Recursive helper for `remove_unreachable_op_nodes`. Performs a depth-first search.
|
|
778
786
|
#
|
|
779
787
|
# Args:
|
|
@@ -181,7 +181,7 @@ class Circuit:
|
|
|
181
181
|
* singleton addition is avoided: add(x) = x,
|
|
182
182
|
* empty addition is avoided: add() = 0,
|
|
183
183
|
"""
|
|
184
|
-
to_add = tuple(n for n in self._check_nodes(args) if not n.is_zero
|
|
184
|
+
to_add = tuple(n for n in self._check_nodes(args) if not n.is_zero)
|
|
185
185
|
match len(to_add):
|
|
186
186
|
case 0:
|
|
187
187
|
return self.zero
|
|
@@ -200,8 +200,8 @@ class Circuit:
|
|
|
200
200
|
* singleton multiplication is avoided: mul(x) = x,
|
|
201
201
|
* empty multiplication is avoided: mul() = 1,
|
|
202
202
|
"""
|
|
203
|
-
to_mul = tuple(n for n in self._check_nodes(args) if not n.is_one
|
|
204
|
-
if any(n.is_zero
|
|
203
|
+
to_mul = tuple(n for n in self._check_nodes(args) if not n.is_one)
|
|
204
|
+
if any(n.is_zero for n in to_mul):
|
|
205
205
|
return self.zero
|
|
206
206
|
match len(to_mul):
|
|
207
207
|
case 0:
|
|
@@ -485,12 +485,14 @@ class CircuitNode:
|
|
|
485
485
|
def __init__(self, circuit: Circuit):
|
|
486
486
|
self.circuit = circuit
|
|
487
487
|
|
|
488
|
+
@property
|
|
488
489
|
def is_zero(self) -> bool:
|
|
489
490
|
"""
|
|
490
491
|
Does this node represent the constant zero.
|
|
491
492
|
"""
|
|
492
493
|
return False
|
|
493
494
|
|
|
495
|
+
@property
|
|
494
496
|
def is_one(self) -> bool:
|
|
495
497
|
"""
|
|
496
498
|
Does this node represent the constant one.
|
|
@@ -522,10 +524,12 @@ class ConstNode(CircuitNode):
|
|
|
522
524
|
def value(self) -> ConstValue:
|
|
523
525
|
return self._value
|
|
524
526
|
|
|
527
|
+
@property
|
|
525
528
|
def is_zero(self) -> bool:
|
|
526
529
|
# noinspection PyProtectedMember
|
|
527
530
|
return self is self.circuit.zero
|
|
528
531
|
|
|
532
|
+
@property
|
|
529
533
|
def is_one(self) -> bool:
|
|
530
534
|
# noinspection PyProtectedMember
|
|
531
535
|
return self is self.circuit.one
|
|
@@ -569,11 +573,13 @@ class VarNode(CircuitNode):
|
|
|
569
573
|
else:
|
|
570
574
|
self._const = self.circuit.const(value)
|
|
571
575
|
|
|
576
|
+
@property
|
|
572
577
|
def is_zero(self) -> bool:
|
|
573
|
-
return self._const is not None and self._const.is_zero
|
|
578
|
+
return self._const is not None and self._const.is_zero
|
|
574
579
|
|
|
580
|
+
@property
|
|
575
581
|
def is_one(self) -> bool:
|
|
576
|
-
return self._const is not None and self._const.is_one
|
|
582
|
+
return self._const is not None and self._const.is_one
|
|
577
583
|
|
|
578
584
|
def __lt__(self, other) -> bool:
|
|
579
585
|
if isinstance(other, VarNode):
|
|
@@ -707,9 +713,11 @@ class _DerivativeHelper:
|
|
|
707
713
|
to_add: Sequence[CircuitNode] = tuple(
|
|
708
714
|
value
|
|
709
715
|
for value in (self._derivative_prod(prods) for prods in d_node.sum_prod)
|
|
710
|
-
if not value.is_zero
|
|
716
|
+
if not value.is_zero
|
|
711
717
|
)
|
|
712
718
|
# We can release the temporary memory at this DNode now
|
|
719
|
+
# Warning disabled as we will never use this field again - doing so would be an error.
|
|
720
|
+
# noinspection PyTypeChecker
|
|
713
721
|
d_node.sum_prod = None
|
|
714
722
|
|
|
715
723
|
# Construct the addition operation
|