compiled-knowledge 4.0.0a24__cp312-cp312-macosx_11_0_arm64.whl → 4.1.0__cp312-cp312-macosx_11_0_arm64.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 (58) hide show
  1. ck/circuit/_circuit_cy.c +1 -1
  2. ck/circuit/_circuit_cy.cpython-312-darwin.so +0 -0
  3. ck/circuit/tmp_const.py +5 -4
  4. ck/circuit_compiler/cython_vm_compiler/_compiler.c +152 -152
  5. ck/circuit_compiler/cython_vm_compiler/_compiler.cpython-312-darwin.so +0 -0
  6. ck/circuit_compiler/interpret_compiler.py +2 -2
  7. ck/circuit_compiler/llvm_compiler.py +4 -4
  8. ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.c +1 -1
  9. ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.cpython-312-darwin.so +0 -0
  10. ck/circuit_compiler/support/input_vars.py +4 -4
  11. ck/circuit_compiler/support/llvm_ir_function.py +4 -4
  12. ck/dataset/__init__.py +1 -0
  13. ck/dataset/cross_table.py +334 -0
  14. ck/dataset/dataset.py +682 -0
  15. ck/dataset/dataset_builder.py +519 -0
  16. ck/dataset/dataset_compute.py +140 -0
  17. ck/dataset/dataset_from_crosstable.py +64 -0
  18. ck/dataset/dataset_from_csv.py +151 -0
  19. ck/dataset/sampled_dataset.py +96 -0
  20. ck/example/diamond_square.py +3 -1
  21. ck/example/triangle_square.py +3 -1
  22. ck/example/truss.py +3 -1
  23. ck/in_out/parse_net.py +21 -19
  24. ck/in_out/parser_utils.py +7 -3
  25. ck/learning/__init__.py +0 -0
  26. ck/learning/coalesce_cross_tables.py +403 -0
  27. ck/learning/model_from_cross_tables.py +296 -0
  28. ck/learning/parameters.py +117 -0
  29. ck/learning/train_generative_bn.py +198 -0
  30. ck/pgm.py +105 -92
  31. ck/pgm_circuit/marginals_program.py +5 -0
  32. ck/pgm_circuit/mpe_program.py +3 -4
  33. ck/pgm_circuit/pgm_circuit.py +27 -18
  34. ck/pgm_circuit/program_with_slotmap.py +27 -46
  35. ck/pgm_circuit/support/compile_circuit.py +2 -4
  36. ck/pgm_circuit/wmc_program.py +5 -0
  37. ck/pgm_compiler/support/circuit_table/_circuit_table_cy.c +1 -1
  38. ck/pgm_compiler/support/circuit_table/_circuit_table_cy.cpython-312-darwin.so +0 -0
  39. ck/probability/cross_table_probability_space.py +53 -0
  40. ck/probability/divergence.py +226 -0
  41. ck/probability/empirical_probability_space.py +1 -0
  42. ck/probability/probability_space.py +53 -30
  43. ck/program/raw_program.py +23 -16
  44. ck/sampling/sampler_support.py +5 -6
  45. ck/utils/iter_extras.py +3 -2
  46. ck/utils/local_config.py +16 -8
  47. ck_demos/dataset/__init__.py +0 -0
  48. ck_demos/dataset/demo_dataset_builder.py +37 -0
  49. ck_demos/dataset/demo_dataset_from_sampler.py +18 -0
  50. ck_demos/learning/__init__.py +0 -0
  51. ck_demos/learning/demo_bayesian_network_from_cross_tables.py +70 -0
  52. ck_demos/learning/demo_simple_learning.py +55 -0
  53. ck_demos/sampling/demo_wmc_direct_sampler.py +2 -2
  54. {compiled_knowledge-4.0.0a24.dist-info → compiled_knowledge-4.1.0.dist-info}/METADATA +2 -1
  55. {compiled_knowledge-4.0.0a24.dist-info → compiled_knowledge-4.1.0.dist-info}/RECORD +58 -37
  56. {compiled_knowledge-4.0.0a24.dist-info → compiled_knowledge-4.1.0.dist-info}/WHEEL +0 -0
  57. {compiled_knowledge-4.0.0a24.dist-info → compiled_knowledge-4.1.0.dist-info}/licenses/LICENSE.txt +0 -0
  58. {compiled_knowledge-4.0.0a24.dist-info → compiled_knowledge-4.1.0.dist-info}/top_level.txt +0 -0
ck/pgm.py CHANGED
@@ -15,33 +15,34 @@ from ck.utils.iter_extras import (
15
15
  from ck.utils.np_extras import NDArrayFloat64, NDArrayUInt8
16
16
 
17
17
  State: TypeAlias = Union[int, str, bool, float, None]
18
- State.__doc__ = \
19
- """
20
- The type for a possible state of a random variable.
21
- """
22
-
23
- Instance: TypeAlias = Sequence[int]
24
- Instance.__doc__ = \
25
- """
26
- An instance (of a sequence of random variables) is a sequence of integers
27
- that are state indexes, co-indexed with a known sequence of random variables.
28
- """
29
-
30
- Key: TypeAlias = Union[Instance, int]
31
- Key.__doc__ = \
32
- """
33
- A key identifies an instance, either as an instance itself or a
34
- single integer, representing an instance with one dimension.
35
- """
18
+ """
19
+ The type for a possible state of a random variable.
20
+ """
21
+
22
+ Instance: TypeAlias = Tuple[int, ...]
23
+ """
24
+ An instance (of a sequence of random variables) is a tuple of integers
25
+ that are state indexes, co-indexed with a known sequence of random variables.
26
+ """
27
+
28
+ Key: TypeAlias = Union[Sequence[int], int]
29
+ """
30
+ A key identifies an instance, either as a sequence of integers or a
31
+ single integer. The integers are state indexes, co-indexed with a known
32
+ sequence of random variables. A single integer represents an instance with
33
+ one dimension.
34
+ """
36
35
 
37
36
  Shape: TypeAlias = Sequence[int]
38
- Key.__doc__ = \
39
- """
40
- The type for the "shape" of a sequence of random variables.
41
- That is, the shape of (rv1, rv2, rv3) is (len(rv1), len(rv2), len(rv3)).
42
- """
37
+ """
38
+ The type for the "shape" of a sequence of random variables.
39
+ That is, the shape of (rv1, rv2, rv3) is (len(rv1), len(rv2), len(rv3)).
40
+ """
43
41
 
44
- DEFAULT_CPT_TOLERANCE: float = 0.000001 # A tolerance when checking CPT distributions sum to one (or zero).
42
+ DEFAULT_CPT_TOLERANCE: float = 0.000001
43
+ """
44
+ A tolerance when checking CPT distributions sum to one (or zero).
45
+ """
45
46
 
46
47
 
47
48
  class PGM:
@@ -214,14 +215,17 @@ class PGM:
214
215
  The returned random variable will have an `idx` equal to the value of
215
216
  `self.number_of_rvs` just prior to adding the new random variable.
216
217
 
218
+ The states of the random variable can be specified either as an integer
219
+ representing the number of states, or as a sequence of state values. If a
220
+ single integer, `n`, is provided then the states will be: 0, 1, ..., n-1.
221
+ If a sequence of states are provided then the states must be unique.
222
+
217
223
  Assumes:
218
224
  Provided states contain no duplicates.
219
225
 
220
226
  Args:
221
227
  name: a name for the random variable.
222
- states: either an integer number of states or a sequence of state values. If a
223
- single integer, `n`, is provided then the states will be 0, 1, ..., n-1.
224
- If a sequence of states are provided then the states must be unique.
228
+ states: either the number of states or a sequence of state values.
225
229
 
226
230
  Returns:
227
231
  a RandomVariable object belonging to this PGM.
@@ -241,10 +245,11 @@ class PGM:
241
245
 
242
246
  Assumes:
243
247
  The given random variables all belong to this PGM.
248
+
244
249
  The random variables contain no duplicates.
245
250
 
246
251
  Args:
247
- *rvs: the random variables.
252
+ rvs: the random variables.
248
253
 
249
254
  Returns:
250
255
  a Factor object belonging to this PGM.
@@ -336,17 +341,18 @@ class PGM:
336
341
  *input_rvs: RandomVariable
337
342
  ) -> Factor:
338
343
  """
339
- Add a sparse 0/1 factor to this PGM representing:
340
- result_rv == function(*rvs).
341
- That is:
344
+ Add a sparse 0/1 factor to this PGM representing `result_rv == function(*rvs)`.
345
+ That is::
346
+
342
347
  factor[result_s, *input_s] = 1, if result_s == function(*input_s);
343
348
  = 0, otherwise.
349
+
344
350
  Args:
345
351
  function: a function from state indexes of the input random variables to a state index
346
352
  of the result random variable. The function should take the same number of arguments
347
353
  as `input_rvs` and return a state index for `result_rv`.
348
354
  result_rv: the random variable defining result values.
349
- *input_rvs: the random variables defining input values.
355
+ input_rvs: the random variables defining input values.
350
356
 
351
357
  Returns:
352
358
  a Factor object belonging to this PGM, with a configured sparse potential function.
@@ -378,16 +384,17 @@ class PGM:
378
384
  """
379
385
  Render indicators as a string.
380
386
 
381
- For example:
387
+ For example::
382
388
  pgm = PGM()
383
389
  a = pgm.new_rv('A', ('x', 'y', 'z'))
384
390
  b = pgm.new_rv('B', (3, 5))
385
391
  print(pgm.indicator_str(a[0], b[1], a[2]))
386
- will print:
392
+
393
+ will print::
387
394
  A=x, B=5, A=z
388
395
 
389
396
  Args:
390
- *indicators: the indicators to render.
397
+ indicators: the indicators to render.
391
398
  sep: the separator to use between the random variable and its state.
392
399
  delim: the delimiter to used when rendering multiple indicators.
393
400
 
@@ -406,16 +413,17 @@ class PGM:
406
413
  """
407
414
  Render indicators as a string, grouping indicators by random variable.
408
415
 
409
- For example:
416
+ For example::
410
417
  pgm = PGM()
411
418
  a = pgm.new_rv('A', ('x', 'y', 'z'))
412
419
  b = pgm.new_rv('B', (3, 5))
413
420
  print(pgm.condition_str(a[0], b[1], a[2]))
414
- will print:
421
+
422
+ will print::
415
423
  A in {x, z}, B=5
416
424
 
417
425
  Args:
418
- *indicators: the indicators to render.
426
+ indicators: the indicators to render.
419
427
  Return:
420
428
  a string representation of the given indicators, as a condition.
421
429
  """
@@ -588,9 +596,11 @@ class PGM:
588
596
 
589
597
  # Factors form a DAG
590
598
  states: NDArrayUInt8 = np.zeros(self.number_of_factors, dtype=np.uint8)
591
- for factor in self._factors:
592
- if self._has_cycle(factor, child_to_factor, states):
593
- return False
599
+ if any(
600
+ self._has_cycle(factor, child_to_factor, states)
601
+ for factor in self._factors
602
+ ):
603
+ return False
594
604
 
595
605
  # All tests passed
596
606
  return True
@@ -770,7 +780,7 @@ class PGM:
770
780
  next_prefix: str = prefix + indent
771
781
  next_next_prefix: str = next_prefix + indent
772
782
 
773
- print(f'{prefix}PGM id={id(self)} name={self.name!r}')
783
+ print(f'{prefix}PGM id={id(self)}')
774
784
  self.dump_synopsis(prefix=next_prefix, precision=precision, max_state_digits=max_state_digits)
775
785
 
776
786
  print(f'{prefix}random variables ({self.number_of_rvs})')
@@ -784,16 +794,16 @@ class PGM:
784
794
 
785
795
  print(f'{prefix}factors ({self.number_of_factors})')
786
796
  for factor in self.factors:
787
- rv_idxs = [rv.idx for rv in factor.rvs]
797
+ factor_rvs = ', '.join(repr(rv.name) for rv in factor.rvs)
788
798
  if factor.is_zero:
789
- function_ref = '<zero>'
799
+ function_ref = '<ZeroPotentialFunction>'
790
800
  else:
791
801
  function = factor.function
792
802
  function_ref = f'{id(function)}: {function.__class__.__name__}'
793
803
 
794
- print(f'{next_prefix}{factor.idx:>3} rvs={rv_idxs} function={function_ref}')
804
+ print(f'{next_prefix}{factor.idx:>3} rvs=({factor_rvs}) function={function_ref}')
795
805
 
796
- print(f'{prefix}functions ({self.number_of_functions})')
806
+ print(f'{prefix}functions, excluding ZeroPotentialFunction ({sum(1 for _ in self.non_zero_functions)})')
797
807
  for function in sorted(self.non_zero_functions, key=lambda f: id(f)):
798
808
  print(f'{next_prefix}{id(function):>13}: {function.__class__.__name__}')
799
809
  function.dump(prefix=next_next_prefix, show_function_values=show_function_values, show_id_class=False)
@@ -930,9 +940,9 @@ class RandomVariable(Sequence[Indicator]):
930
940
  in the random variable's PGM list of random variables.
931
941
 
932
942
  A random variable behaves like a sequence of Indicators, where each indicator represents a random
933
- variable being in a particular state. Specifically for a random variable rv, len(rv) is the
943
+ variable being in a particular state. Specifically for a random variable rv, `len(rv)` is the
934
944
  number of states of the random variable and rv[i] is the Indicators representing that
935
- rv is in the ith state. When sliced, the result is a tuple, i.e. rv[1:3] = (rv[1], rv[2]).
945
+ rv is in the ith state. When sliced, the result is a tuple, i.e. `rv[1:3] = (rv[1], rv[2])`.
936
946
 
937
947
  A RandomVariable has a name. This is for human convenience and has no functional purpose
938
948
  within a PGM.
@@ -942,15 +952,18 @@ class RandomVariable(Sequence[Indicator]):
942
952
  """
943
953
  Create a new random variable, in the given PGM.
944
954
 
955
+ The states of the random variable can be specified either as an integer
956
+ representing the number of states, or as a sequence of state values. If a
957
+ single integer, `n`, is provided then the states will be: 0, 1, ..., n-1.
958
+ If a sequence of states are provided then the states must be unique.
959
+
945
960
  Assumes:
946
961
  Provided states contain no duplicates.
947
962
 
948
963
  Args:
949
964
  pgm: the PGM that the random variable will belong to.
950
965
  name: a name for the random variable.
951
- states: either an integer number of states or a sequence of state values. If a
952
- single integer, `n`, is provided then the states will be 0, 1, ..., n-1.
953
- If a sequence of states are provided then the states must be unique.
966
+ states: either the number of states or a sequence of state values.
954
967
  """
955
968
  self._pgm: PGM = pgm
956
969
  self._name: str = name
@@ -1212,15 +1225,14 @@ class RVMap(Sequence[RandomVariable]):
1212
1225
  In addition to accessing a random variable by its index, an RVMap enables
1213
1226
  access to the PGM random variable via the name of each random variable.
1214
1227
 
1215
- For example, if `pgm.rvs[1]` is a random variable named `xray`, then:
1216
- ```
1217
- rvs = RVMap(pgm)
1228
+ For example, if `pgm.rvs[1]` is a random variable named `xray`, then::
1218
1229
 
1219
- # These all retrieve the same random variable object.
1220
- xray = rvs[1]
1221
- xray = rvs('xray')
1222
- xray = rvs.xray
1223
- ```
1230
+ rvs = RVMap(pgm)
1231
+
1232
+ # These all retrieve the same random variable object.
1233
+ xray = rvs[1]
1234
+ xray = rvs('xray')
1235
+ xray = rvs.xray
1224
1236
 
1225
1237
  To use an RVMap on a PGM, the random variable names must be unique across the PGM.
1226
1238
  """
@@ -1527,7 +1539,7 @@ class Factor:
1527
1539
  Set to the potential function to a new `ClausePotentialFunction` object.
1528
1540
 
1529
1541
  Args:
1530
- *key: defines the random variable states of the clause. The key is a sequence of
1542
+ key: defines the random variable states of the clause. The key is a sequence of
1531
1543
  random variable state indexes, co-indexed with `Factor.rvs`.
1532
1544
 
1533
1545
  Returns:
@@ -1556,7 +1568,7 @@ class Factor:
1556
1568
  return self._potential_function
1557
1569
 
1558
1570
 
1559
- @dataclass(frozen=True, eq=True)
1571
+ @dataclass(frozen=True, eq=True, slots=True)
1560
1572
  class ParamId:
1561
1573
  """
1562
1574
  A ParamId identifies a parameter of a potential function.
@@ -1863,7 +1875,7 @@ class PotentialFunction(ABC):
1863
1875
  a hypothetical parameter index assuming that every valid key has a unique parameter
1864
1876
  as per DensePotentialFunction.
1865
1877
  """
1866
- return _natural_key_idx(self._shape, key)
1878
+ return natural_key_idx(self._shape, key)
1867
1879
 
1868
1880
  def param_id(self, param_idx: int) -> ParamId:
1869
1881
  """
@@ -2021,7 +2033,7 @@ class ZeroPotentialFunction(PotentialFunction):
2021
2033
  return 0
2022
2034
 
2023
2035
  def param_idx(self, key: Key) -> int:
2024
- return _natural_key_idx(self._shape, key)
2036
+ return natural_key_idx(self._shape, key)
2025
2037
 
2026
2038
  def is_cpt(self, tolerance=DEFAULT_CPT_TOLERANCE) -> bool:
2027
2039
  return True
@@ -2164,7 +2176,7 @@ class DensePotentialFunction(PotentialFunction):
2164
2176
  """
2165
2177
  Set the values of the potential function using the given iterator.
2166
2178
 
2167
- Mapping instances to *values is as follows:
2179
+ Mapping instances to values is as follows:
2168
2180
  Given Factor(rv1, rv2) where rv1 has 2 states, and rv2 has 3 states:
2169
2181
  values[0] represents instance (0,0)
2170
2182
  values[1] represents instance (0,1)
@@ -2209,7 +2221,7 @@ class DensePotentialFunction(PotentialFunction):
2209
2221
  The order of values is the same as set_iter.
2210
2222
 
2211
2223
  Args:
2212
- *value: the values to use.
2224
+ value: the values to use.
2213
2225
 
2214
2226
  Returns:
2215
2227
  self
@@ -2414,7 +2426,7 @@ class SparsePotentialFunction(PotentialFunction):
2414
2426
  """
2415
2427
  Set the values of the potential function using the given iterator.
2416
2428
 
2417
- Mapping instances to *values is as follows:
2429
+ Mapping instances to values is as follows:
2418
2430
  Given Factor(rv1, rv2) where rv1 has 2 states, and rv2 has 3 states:
2419
2431
  values[0] represents instance (0,0)
2420
2432
  values[1] represents instance (0,1)
@@ -2636,7 +2648,7 @@ class CompactPotentialFunction(PotentialFunction):
2636
2648
  """
2637
2649
  Set the values of the potential function using the given iterator.
2638
2650
 
2639
- Mapping instances to *values is as follows:
2651
+ Mapping instances to `values` is as follows:
2640
2652
  Given Factor(rv1, rv2) where rv1 has 2 states, and rv2 has 3 states:
2641
2653
  values[0] represents instance (0,0)
2642
2654
  values[1] represents instance (0,1)
@@ -2679,7 +2691,7 @@ class CompactPotentialFunction(PotentialFunction):
2679
2691
  The order of values is the same as set_iter.
2680
2692
 
2681
2693
  Args:
2682
- *value: the values to use.
2694
+ value: the values to use.
2683
2695
 
2684
2696
  Returns:
2685
2697
  self
@@ -3071,7 +3083,8 @@ class CPTPotentialFunction(PotentialFunction):
3071
3083
  Calls self.set_cpd(parent_states, cpd) for each row (parent_states, cpd)
3072
3084
  in rows. Any unmentioned parent states will have zero probabilities.
3073
3085
 
3074
- Example usage, assuming three Boolean random variables:
3086
+ Example usage, assuming three Boolean random variables::
3087
+
3075
3088
  pgm.Factor(x, y, z).set_cpt().set(
3076
3089
  # y z x[0] x[1]
3077
3090
  ((0, 0), (0.1, 0.9)),
@@ -3079,9 +3092,9 @@ class CPTPotentialFunction(PotentialFunction):
3079
3092
  ((1, 0), (0.1, 0.9)),
3080
3093
  ((1, 1), (0.1, 0.9))
3081
3094
  )
3082
-
3095
+
3083
3096
  Args:
3084
- *rows: are tuples (key, cpd) used to set the potential function values.
3097
+ rows: are tuples (key, cpd) used to set the potential function values.
3085
3098
 
3086
3099
  Raises:
3087
3100
  ValueError: if a CPD is not valid.
@@ -3105,7 +3118,7 @@ class CPTPotentialFunction(PotentialFunction):
3105
3118
  Any list entry may be None, indicating 'guaranteed zero' for the associated parent states.
3106
3119
 
3107
3120
  Args:
3108
- *cpds: are the CPDs used to set the potential function values.
3121
+ cpds: are the CPDs used to set the potential function values.
3109
3122
 
3110
3123
  Raises:
3111
3124
  ValueError: if a CPD is not valid.
@@ -3355,26 +3368,7 @@ def rv_instances_as_indicators(*rvs: RandomVariable, flip: bool = False) -> Iter
3355
3368
  return _combos(rvs, flip=not flip)
3356
3369
 
3357
3370
 
3358
- def _key_to_instance(key: Key) -> Instance:
3359
- """
3360
- Convert a key to an instance.
3361
-
3362
- Args:
3363
- key: a key into a state space.
3364
-
3365
- Returns:
3366
- A instance from the state space, as a tuple of state indexes, co-indexed with the given shape.
3367
-
3368
- Assumes:
3369
- The key is valid for the implied state space.
3370
- """
3371
- if isinstance(key, int):
3372
- return (key,)
3373
- else:
3374
- return tuple(key)
3375
-
3376
-
3377
- def _natural_key_idx(shape: Shape, key: Key) -> int:
3371
+ def natural_key_idx(shape: Shape, key: Key) -> int:
3378
3372
  """
3379
3373
  What is the natural index of the given key, assuming the given shape.
3380
3374
 
@@ -3400,6 +3394,25 @@ def _natural_key_idx(shape: Shape, key: Key) -> int:
3400
3394
  return result
3401
3395
 
3402
3396
 
3397
+ def _key_to_instance(key: Key) -> Instance:
3398
+ """
3399
+ Convert a key to an instance.
3400
+
3401
+ Args:
3402
+ key: a key into a state space.
3403
+
3404
+ Returns:
3405
+ A instance from the state space, as a tuple of state indexes, co-indexed with the given shape.
3406
+
3407
+ Assumes:
3408
+ The key is valid for the implied state space.
3409
+ """
3410
+ if isinstance(key, int):
3411
+ return (key,)
3412
+ else:
3413
+ return tuple(key)
3414
+
3415
+
3403
3416
  def _zero_space(shape: Shape) -> int:
3404
3417
  """
3405
3418
  Return the size of the zero space of the given shape. This is the number
@@ -308,6 +308,11 @@ class MarginalsProgram(ProgramWithSlotmap, ProbabilitySpace):
308
308
  The sampler will yield state lists, where the state
309
309
  values are co-indexed with rvs, or self.rvs if rvs is None.
310
310
 
311
+ For more information about this sampler, see the publication:
312
+ Suresh, S., Drake, B. (2025). Sampling of Large Probabilistic Graphical Models
313
+ Using Arithmetic Circuits. AI 2024: Advances in Artificial Intelligence. AI 2024.
314
+ Lecture Notes in Computer Science, vol 15443. https://doi.org/10.1007/978-981-96-0351-0_13.
315
+
311
316
  Args:
312
317
  rvs: the list of random variables to sample; the
313
318
  yielded state vectors are co-indexed with rvs; if None,
@@ -228,10 +228,9 @@ class MPEProgram(ProgramWithSlotmap):
228
228
  class MPEResult:
229
229
  """
230
230
  An MPE result is the result of MPE inference.
231
-
232
- Fields:
233
- wmc: the weighted model count value of the MPE solution.
234
- mpe: The MPE solution instance. If there are ties then this will just be once instance.
235
231
  """
236
232
  wmc: float
233
+ """the weighted model count value of the MPE solution."""
234
+
237
235
  mpe: Instance
236
+ """the MPE solution instance. If there are ties then this will just be once instance."""
@@ -16,33 +16,42 @@ class PGMCircuit:
16
16
  holds the values of the parameters. Specifically, given parameter id `param_id`, then
17
17
  `parameter_values[slot_map[param_id] - number_of_indicators]` is the value of the
18
18
  identified parameter as it was in the PGM.
19
-
20
- Fields:
21
- rvs: holds the random variables from the PGM as it was compiled, in order.
22
-
23
- conditions: any conditions on `rvs` that were compiled into the circuit.
24
-
25
- number_of_indicators: is the number of indicators in `rvs` which is
26
- `sum(len(rv) for rv in rvs`. Specifically, `circuit.vars[i]` is the circuit variable
27
- corresponding to the ith indicator, where `circuit` is `circuit_top.circuit` and
28
- indicators are ordered as per `rvs`.
29
-
30
- number_of_parameters: is the number of parameters from the PGM that are
31
- represented as circuit variables. This may be zero if parameters from the PGM
32
- were compiled as constants.
33
-
34
- slot_map[x]: gives the index of the circuit variable corresponding to x,
35
- where x is either a random variable indicator (Indicator) or a parameter id (ParamId).
36
-
37
19
  """
38
20
 
39
21
  rvs: Sequence[RandomVariable]
22
+ """holds the random variables from the PGM as it was compiled, in order."""
23
+
40
24
  conditions: Sequence[Indicator]
25
+ """any conditions on `rvs` that were compiled into the circuit."""
26
+
41
27
  circuit_top: CircuitNode
28
+ """the top circuit node defining the network function."""
29
+
42
30
  number_of_indicators: int
31
+ """
32
+ the number of indicators in `rvs` which is
33
+ `sum(len(rv) for rv in rvs`. Specifically, `circuit.vars[i]` is the circuit variable
34
+ corresponding to the ith indicator, where `circuit` is `circuit_top.circuit` and
35
+ indicators are ordered as per `rvs`.
36
+ """
37
+
43
38
  number_of_parameters: int
39
+ """
40
+ the number of parameters from the PGM that are
41
+ represented as circuit variables. This may be zero if parameters from the PGM
42
+ were compiled as constants.
43
+ """
44
+
44
45
  slot_map: SlotMap
46
+ """
47
+ gives the index of the circuit variable corresponding to x,
48
+ where x is either a random variable indicator (Indicator) or a parameter id (ParamId).
49
+ """
50
+
45
51
  parameter_values: NDArray
52
+ """
53
+ parameter values, co-indexed with the circuit variables, counting beyond `number_of_indicators`.
54
+ """
46
55
 
47
56
  def dump(self, *, prefix: str = '', indent: str = ' ') -> None:
48
57
  """
@@ -1,6 +1,8 @@
1
- from typing import Tuple, Sequence, Dict, Iterable
1
+ from typing import Tuple, Sequence, Dict
2
2
 
3
- from ck.pgm import RandomVariable, rv_instances, Instance, rv_instances_as_indicators, Indicator, ParamId
3
+ import numpy as np
4
+
5
+ from ck.pgm import RandomVariable, Indicator, ParamId
4
6
  from ck.pgm_circuit.slot_map import SlotMap, SlotKey
5
7
  from ck.probability.probability_space import Condition, check_condition
6
8
  from ck.program.program_buffer import ProgramBuffer
@@ -69,40 +71,6 @@ class ProgramWithSlotmap:
69
71
  def slot_map(self) -> SlotMap:
70
72
  return self._slot_map
71
73
 
72
- def instances(self, flip: bool = False) -> Iterable[Instance]:
73
- """
74
- Enumerate instances of the random variables.
75
-
76
- Each instance is a tuples of state indexes, co-indexed with the given random variables.
77
-
78
- The order is the natural index order (i.e., last random variable changing most quickly).
79
-
80
- Args:
81
- flip: if true, then first random variable changes most quickly.
82
-
83
- Returns:
84
- an iteration over tuples, each tuple holds state indexes
85
- co-indexed with the given random variables.
86
- """
87
- return rv_instances(*self._rvs, flip=flip)
88
-
89
- def instances_as_indicators(self, flip: bool = False) -> Iterable[Sequence[Indicator]]:
90
- """
91
- Enumerate instances of the random variables.
92
-
93
- Each instance is a tuples of indicators, co-indexed with the given random variables.
94
-
95
- The order is the natural index order (i.e., last random variable changing most quickly).
96
-
97
- Args:
98
- flip: if true, then first random variable changes most quickly.
99
-
100
- Returns:
101
- an iteration over tuples, each tuples holds random variable indicators
102
- co-indexed with the given random variables.
103
- """
104
- return rv_instances_as_indicators(*self._rvs, flip=flip)
105
-
106
74
  def compute(self) -> NDArrayNumeric:
107
75
  """
108
76
  Execute the program to compute and return the result. As per `ProgramBuffer.compute`.
@@ -114,7 +82,10 @@ class ProgramWithSlotmap:
114
82
 
115
83
  def compute_conditioned(self, *condition: Condition) -> NDArrayNumeric:
116
84
  """
117
- Equivalent to:
85
+ Compute the program value, after setting the given condition.
86
+
87
+ Equivalent to::
88
+
118
89
  self.set_condition(*condition)
119
90
  return self.compute()
120
91
  """
@@ -143,29 +114,36 @@ class ProgramWithSlotmap:
143
114
  """
144
115
  return self._program_buffer.vars
145
116
 
146
- def __setitem__(self, item: int | slice | SlotKey | Iterable[SlotKey], value: float) -> None:
117
+ def __setitem__(self, item: int | slice | SlotKey | RandomVariable, value: float) -> None:
147
118
  """
148
- Set one or more input slot values, identified by slot keys.
119
+ Set input slot value/s.
149
120
  """
150
121
  if isinstance(item, (int, slice)):
151
122
  self._program_buffer[item] = value
152
123
  elif isinstance(item, (Indicator, ParamId)):
153
124
  self._program_buffer[self._slot_map[item]] = value
125
+ elif isinstance(item, RandomVariable):
126
+ for ind in item:
127
+ self._program_buffer[self._slot_map[ind]] = value
154
128
  else:
155
- # Assume its iterable
156
- for i in item:
157
- self[i] = value
129
+ raise IndexError(f'unknown index type: {type(item)}')
158
130
 
159
- def __getitem__(self, item: int | slice | SlotKey) -> NDArrayNumeric:
131
+ def __getitem__(self, item: int | slice | SlotKey | RandomVariable) -> NDArrayNumeric:
160
132
  """
161
- Get an input slot value, identified by a slot key.
133
+ Get input slot value/s.
162
134
  """
163
135
  if isinstance(item, (int, slice)):
164
136
  return self._program_buffer[item]
165
137
  elif isinstance(item, (Indicator, ParamId)):
166
138
  return self._program_buffer[self._slot_map[item]]
139
+ elif isinstance(item, RandomVariable):
140
+ return np.fromiter(
141
+ (self._program_buffer[self._slot_map[ind]] for ind in item),
142
+ dtype=self._program_buffer.dtype,
143
+ count=len(item)
144
+ )
167
145
  else:
168
- raise IndexError('unknown index type')
146
+ raise IndexError(f'unknown index type: {type(item)}')
169
147
 
170
148
  def set_condition(self, *condition: Condition) -> None:
171
149
  """
@@ -208,7 +186,10 @@ class ProgramWithSlotmap:
208
186
 
209
187
  Args:
210
188
  rv: a random variable whose indicators are in the slot map.
211
- values: list of values, assumes len(values) == len(rv).
189
+ values: list of values
190
+
191
+ Assumes:
192
+ len(values) == len(rv).
212
193
  """
213
194
  for i in range(len(rv)):
214
195
  self[rv[i]] = values[i]
@@ -30,11 +30,9 @@ def compile_results(
30
30
  a compiled RawProgram.
31
31
  """
32
32
  circuit: Circuit = pgm_circuit.circuit_top.circuit
33
- if const_parameters:
34
- parameter_values = pgm_circuit.parameter_values
35
- number_of_indicators = pgm_circuit.number_of_indicators
33
+ if const_parameters and len(pgm_circuit.parameter_values) > 0:
36
34
  with TmpConst(circuit) as tmp:
37
- for slot, value in enumerate(parameter_values, start=number_of_indicators):
35
+ for slot, value in enumerate(pgm_circuit.parameter_values, start=pgm_circuit.number_of_indicators):
38
36
  tmp.set_const(slot, value)
39
37
  raw_program: RawProgram = compiler(*results, circuit=circuit)
40
38
  else:
@@ -132,6 +132,11 @@ class WMCProgram(ProgramWithSlotmap, ProbabilitySpace):
132
132
  * calls rand.random() once and rand.randrange(...) n times,
133
133
  * calls self.program().compute_result() at least once and <= 1 + m.
134
134
 
135
+ For more information about this sampler, see the publication:
136
+ Suresh, S., Drake, B. (2025). Sampling of Large Probabilistic Graphical Models
137
+ Using Arithmetic Circuits. AI 2024: Advances in Artificial Intelligence. AI 2024.
138
+ Lecture Notes in Computer Science, vol 15443. https://doi.org/10.1007/978-981-96-0351-0_13.
139
+
135
140
  Args:
136
141
  rvs: the list of random variables to sample; the
137
142
  yielded state vectors are co-indexed with rvs; if None,
@@ -15,7 +15,7 @@
15
15
  "-O3"
16
16
  ],
17
17
  "include_dirs": [
18
- "/private/var/folders/y6/nj790rtn62lfktb1sh__79hc0000gn/T/build-env-gdy6g4em/lib/python3.12/site-packages/numpy/_core/include"
18
+ "/private/var/folders/y6/nj790rtn62lfktb1sh__79hc0000gn/T/build-env-bjhshlet/lib/python3.12/site-packages/numpy/_core/include"
19
19
  ],
20
20
  "name": "ck.pgm_compiler.support.circuit_table._circuit_table_cy",
21
21
  "sources": [