compiled-knowledge 4.0.0a16__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.

Files changed (29) hide show
  1. ck/circuit/__init__.py +2 -2
  2. ck/circuit/_circuit_cy.cp312-win_amd64.pyd +0 -0
  3. ck/circuit/{circuit.pyx → _circuit_cy.pyx} +65 -57
  4. ck/circuit/{circuit_py.py → _circuit_py.py} +14 -6
  5. ck/circuit_compiler/cython_vm_compiler/_compiler.c +1603 -2030
  6. ck/circuit_compiler/cython_vm_compiler/_compiler.cp312-win_amd64.pyd +0 -0
  7. ck/circuit_compiler/cython_vm_compiler/_compiler.pyx +85 -58
  8. ck/circuit_compiler/named_circuit_compilers.py +1 -1
  9. ck/pgm_compiler/factor_elimination.py +23 -13
  10. ck/pgm_compiler/support/circuit_table/__init__.py +2 -2
  11. ck/pgm_compiler/support/circuit_table/_circuit_table_cy.cp312-win_amd64.pyd +0 -0
  12. ck/pgm_compiler/support/circuit_table/{circuit_table.pyx → _circuit_table_cy.pyx} +9 -9
  13. ck/pgm_compiler/support/circuit_table/{circuit_table_py.py → _circuit_table_py.py} +5 -5
  14. ck/pgm_compiler/support/clusters.py +16 -4
  15. ck/pgm_compiler/support/factor_tables.py +1 -1
  16. ck/pgm_compiler/support/join_tree.py +67 -10
  17. ck/pgm_compiler/variable_elimination.py +2 -0
  18. ck_demos/pgm_compiler/demo_compiler_dump.py +10 -0
  19. ck_demos/pgm_compiler/time_fe_compiler.py +93 -0
  20. {compiled_knowledge-4.0.0a16.dist-info → compiled_knowledge-4.0.0a17.dist-info}/METADATA +1 -1
  21. {compiled_knowledge-4.0.0a16.dist-info → compiled_knowledge-4.0.0a17.dist-info}/RECORD +24 -26
  22. ck/circuit/circuit.c +0 -38861
  23. ck/circuit/circuit.cp312-win_amd64.pyd +0 -0
  24. ck/circuit/circuit_node.pyx +0 -138
  25. ck/pgm_compiler/support/circuit_table/circuit_table.c +0 -16042
  26. ck/pgm_compiler/support/circuit_table/circuit_table.cp312-win_amd64.pyd +0 -0
  27. {compiled_knowledge-4.0.0a16.dist-info → compiled_knowledge-4.0.0a17.dist-info}/WHEEL +0 -0
  28. {compiled_knowledge-4.0.0a16.dist-info → compiled_knowledge-4.0.0a17.dist-info}/licenses/LICENSE.txt +0 -0
  29. {compiled_knowledge-4.0.0a16.dist-info → compiled_knowledge-4.0.0a17.dist-info}/top_level.txt +0 -0
ck/circuit/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
- # from .circuit_py import (
2
- from .circuit import (
1
+ # from ._circuit_py import (
2
+ from ._circuit_cy import (
3
3
  Circuit,
4
4
  CircuitNode,
5
5
  VarNode,
@@ -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, Set, Any
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.const(zero)
52
- self.one: ConstNode = self.const(one)
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 object _op(self, int symbol, tuple[CircuitNode, ...] nodes):
128
- cdef object node = OpNode(self, symbol, nodes)
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[object] args = self._check_nodes(nodes)
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[object] args = self._check_nodes(nodes)
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[object] to_add = []
155
- cdef object n
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[object] to_mul = []
178
- cdef object n
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
- seen: Set[int] = set() # set of object ids for all reachable op nodes.
304
- for node in self._check_nodes(nodes):
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
- seen: Set[int] = set() # set of object ids for all reachable op nodes.
332
- result: List[OpNode] = []
333
- for node in self._check_nodes(nodes):
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[object] _check_nodes(self, object nodes: Iterable[Args]): # -> Sequence[CircuitNode]:
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[object] result = []
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[object] result):
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, object f: CircuitNode): # -> _DerivativeHelper:
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 object circuit
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
- cpdef int is_zero(self) except*:
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
- A node in a circuit representing a constant value.
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
- self._const = self.circuit.const(value)
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(object node: CircuitNode, set seen: Set[int], list result: List[OpNode]):
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(object node: CircuitNode, set seen: Set[int]):
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() for n in to_mul):
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