compiled-knowledge 4.0.0a25__cp312-cp312-win32.whl → 4.1.0a2__cp312-cp312-win32.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 (31) hide show
  1. ck/circuit/_circuit_cy.c +1 -1
  2. ck/circuit/_circuit_cy.cp312-win32.pyd +0 -0
  3. ck/circuit_compiler/cython_vm_compiler/_compiler.c +152 -152
  4. ck/circuit_compiler/cython_vm_compiler/_compiler.cp312-win32.pyd +0 -0
  5. ck/circuit_compiler/interpret_compiler.py +2 -2
  6. ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.c +1 -1
  7. ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.cp312-win32.pyd +0 -0
  8. ck/dataset/__init__.py +1 -0
  9. ck/dataset/cross_table.py +270 -0
  10. ck/dataset/cross_table_probabilities.py +53 -0
  11. ck/dataset/dataset.py +594 -0
  12. ck/dataset/dataset_builder.py +512 -0
  13. ck/dataset/dataset_compute.py +140 -0
  14. ck/dataset/dataset_from_crosstable.py +45 -0
  15. ck/dataset/dataset_from_csv.py +151 -0
  16. ck/dataset/sampled_dataset.py +96 -0
  17. ck/learning/__init__.py +0 -0
  18. ck/learning/train_generative.py +149 -0
  19. ck/pgm.py +29 -27
  20. ck/pgm_circuit/program_with_slotmap.py +23 -45
  21. ck/pgm_circuit/support/compile_circuit.py +2 -4
  22. ck/pgm_compiler/support/circuit_table/_circuit_table_cy.c +1 -1
  23. ck/pgm_compiler/support/circuit_table/_circuit_table_cy.cp312-win32.pyd +0 -0
  24. ck/probability/empirical_probability_space.py +1 -0
  25. ck_demos/dataset/__init__.py +0 -0
  26. ck_demos/dataset/demo_dataset_builder.py +37 -0
  27. {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/METADATA +1 -1
  28. {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/RECORD +31 -18
  29. {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/WHEEL +0 -0
  30. {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/licenses/LICENSE.txt +0 -0
  31. {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import ctypes as ct
4
4
  from dataclasses import dataclass
5
- from typing import Sequence, Optional, Dict, List, Tuple, Callable
5
+ from typing import Sequence, Optional, Dict, List, Tuple, Callable, assert_never
6
6
 
7
7
  import numpy as np
8
8
 
@@ -174,7 +174,7 @@ def _make_instructions(
174
174
  elif op_node.symbol == ADD:
175
175
  operation = sum
176
176
  else:
177
- assert False, 'symbol not understood'
177
+ assert_never('not reached')
178
178
 
179
179
  instructions.append(_Instruction(operation, args, dest))
180
180
 
@@ -13,7 +13,7 @@
13
13
  "/O2"
14
14
  ],
15
15
  "include_dirs": [
16
- "C:\\Users\\runneradmin\\AppData\\Local\\Temp\\build-env-8cwjzb8_\\Lib\\site-packages\\numpy\\_core\\include"
16
+ "C:\\Users\\runneradmin\\AppData\\Local\\Temp\\build-env-zvpv36cx\\Lib\\site-packages\\numpy\\_core\\include"
17
17
  ],
18
18
  "name": "ck.circuit_compiler.support.circuit_analyser._circuit_analyser_cy",
19
19
  "sources": [
ck/dataset/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .dataset import Dataset, HardDataset, SoftDataset
@@ -0,0 +1,270 @@
1
+ from typing import List, Tuple, Sequence, Iterator, Iterable, Optional, MutableMapping, Dict
2
+
3
+ from ck.dataset import SoftDataset, HardDataset
4
+ from ck.pgm import RandomVariable, rv_instances, Instance
5
+ from ck.utils.np_extras import NDArray
6
+
7
+
8
+ class CrossTable(MutableMapping[Instance, float]):
9
+ """
10
+ A cross-table records the total weight for possible combinations
11
+ of states for some random variables, i.e., the weight of unique instances.
12
+
13
+ A cross-table is a dictionary mapping from state indices of the cross-table
14
+ random variables (an instance, as a tuple) to a weight (as a float).
15
+
16
+ Given a cross-table `ct`, then for each `instance in ct.keys()`:
17
+ `len(instance) == len(ct.rvs)`,
18
+ and `0 <= instance[j] < len(ct.rvs[i])`,
19
+ and `0 < ct[instance]`.
20
+
21
+ Zero weighted instances are not explicitly represented in a cross-table.
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ rvs: Sequence[RandomVariable],
27
+ dirichlet_prior: float = 0,
28
+ update: Iterable[Tuple[Instance, float]] = (),
29
+ ):
30
+ """
31
+ Construct a cross-table for the given random variables.
32
+
33
+ The cross-table can be initialised with a Dirichlet prior, x. Practically
34
+ this amounts to adding a weight of x to each possible combination of
35
+ random variable states. That is, a Dirichlet prior of x results in x pseudocounts
36
+ for each possible combination of states.
37
+
38
+ Args:
39
+ rvs: the random variables that this cross-table records weights for. Instances
40
+ in this cross-table are tuples of state indexes, co-indexed with `rvs`.
41
+ dirichlet_prior: a real number >= 0, representing a Dirichlet prior.
42
+ update: an optional iterable of (instance, weight) tuples to add to
43
+ the cross-table at construction time.
44
+ """
45
+ self._rvs: Tuple[RandomVariable, ...] = tuple(rvs)
46
+ self._dict: Dict[Instance, float]
47
+
48
+ if dirichlet_prior != 0:
49
+ instance: Tuple[int, ...]
50
+ self._dict = {
51
+ instance: dirichlet_prior
52
+ for instance in rv_instances(*self._rvs)
53
+ }
54
+ else:
55
+ self._dict = {}
56
+
57
+ for instance, weight in update:
58
+ self.add(instance, weight)
59
+
60
+ def __eq__(self, other) -> bool:
61
+ """
62
+ Two cross-tables are equal if they have the same sequence of random variables
63
+ and their instance weights are equal.
64
+ """
65
+ return isinstance(other, CrossTable) and self._rvs == other._rvs and self._dict == other._dict
66
+
67
+ def __setitem__(self, key: Instance, value) -> None:
68
+ if value == 0:
69
+ self._dict.pop(key)
70
+ else:
71
+ self._dict[key] = value
72
+
73
+ def __delitem__(self, key: Instance) -> None:
74
+ del self._dict[key]
75
+
76
+ def __getitem__(self, key: Instance) -> float:
77
+ """
78
+ Returns:
79
+ the weight of the given instance.
80
+ This will always return a value, even if the key is not in the underlying dictionary.
81
+ """
82
+ return self._dict.get(key, 0)
83
+
84
+ def __len__(self) -> int:
85
+ """
86
+ Returns:
87
+ the number of instances in the cross-table with non-zero weight.
88
+ """
89
+ return len(self._dict)
90
+
91
+ def __iter__(self) -> Iterator[Instance]:
92
+ """
93
+ Returns:
94
+ an iterator over the cross-table instances with non-zero weight.
95
+ """
96
+ return iter(self._dict)
97
+
98
+ def items(self) -> Iterable[Tuple[Instance, float]]:
99
+ """
100
+ Returns:
101
+ an iterable over (instance, weight) pairs.
102
+ """
103
+ return self._dict.items()
104
+
105
+ @property
106
+ def rvs(self) -> Sequence[RandomVariable]:
107
+ """
108
+ The random variables that this cross-table refers to.
109
+ """
110
+ return self._rvs
111
+
112
+ def add(self, instance: Instance, weight: float) -> None:
113
+ """
114
+ Add the given weighted instance to the cross-table.
115
+
116
+ Args:
117
+ instance: a tuple of state indices, co-indexed with `self.rvs`.
118
+ weight: the weight (generalised count) to add to the cross-table. Normally the
119
+ weight will be > 0.
120
+ """
121
+ self[instance] = self._dict.get(instance, 0) + weight
122
+
123
+ def total_weight(self) -> float:
124
+ """
125
+ Calculate the total weight of this cross-table.
126
+ """
127
+ return sum(self.values())
128
+
129
+
130
+ def cross_table_from_dataset(
131
+ dataset: HardDataset | SoftDataset,
132
+ rvs: Optional[Sequence[RandomVariable]] = None,
133
+ *,
134
+ dirichlet_prior: float = 0,
135
+ ) -> CrossTable:
136
+ """
137
+ Generate a cross-table for the given random variables, using the given dataset, represented
138
+ as a dictionary, mapping instances to weights.
139
+
140
+ Args:
141
+ dataset: The dataset to use to compute the cross-table.
142
+ rvs: The random variables to compute the cross-table for. If omitted
143
+ then `dataset.rvs` will be used.
144
+ dirichlet_prior: a real number >= 0. See `CrossTable` for an explanation.
145
+
146
+ Returns:
147
+ The cross-table for the given random variables, using the given dataset,
148
+ represented as a dictionary mapping instances to weights.
149
+ An instance is a tuple of state indexes, co-indexed with rvs.
150
+
151
+ Raises:
152
+ KeyError: If any random variable in `rvs` does not appear in the dataset.
153
+ """
154
+ if isinstance(dataset, SoftDataset):
155
+ return cross_table_from_soft_dataset(dataset, rvs, dirichlet_prior=dirichlet_prior)
156
+ if isinstance(dataset, HardDataset):
157
+ return cross_table_from_hard_dataset(dataset, rvs, dirichlet_prior=dirichlet_prior)
158
+ raise TypeError('dataset must be either a SoftDataset or HardDataset')
159
+
160
+
161
+ def cross_table_from_soft_dataset(
162
+ dataset: SoftDataset,
163
+ rvs: Optional[Sequence[RandomVariable]] = None,
164
+ *,
165
+ dirichlet_prior: float = 0
166
+ ) -> CrossTable:
167
+ """
168
+ Generate a cross-table for the given random variables, using the given dataset, represented
169
+ as a dictionary, mapping instances to weights.
170
+
171
+ Args:
172
+ dataset: The dataset to use to compute the cross-table.
173
+ rvs: The random variables to compute the cross-table for. If omitted
174
+ then `dataset.rvs` will be used.
175
+ dirichlet_prior: a real number >= 0. See `CrossTable` for an explanation.
176
+
177
+ Returns:
178
+ The cross-table for the given random variables, using the given dataset,
179
+ represented as a dictionary mapping instances to weights.
180
+ An instance is a tuple of state indexes, co-indexed with rvs.
181
+
182
+ Raises:
183
+ KeyError: If any random variable in `rvs` does not appear in the dataset.
184
+ """
185
+ if rvs is None:
186
+ rvs = dataset.rvs
187
+
188
+ # Special case
189
+ if len(rvs) == 0:
190
+ return CrossTable((), 0, [((), dataset.total_weight() + dirichlet_prior)])
191
+
192
+ weights: CrossTable = CrossTable(rvs, dirichlet_prior)
193
+
194
+ columns: List[NDArray] = [
195
+ dataset.state_weights(rv)
196
+ for rv in rvs
197
+ ]
198
+
199
+ for instance_weights, weight in zip(zip(*columns), dataset.weights):
200
+ if weight != 0:
201
+ for instance, instance_weight in _product_instance_weights(instance_weights):
202
+ weights.add(instance, instance_weight * weight)
203
+
204
+ return weights
205
+
206
+
207
+ def cross_table_from_hard_dataset(
208
+ dataset: HardDataset,
209
+ rvs: Optional[Sequence[RandomVariable]] = None,
210
+ *,
211
+ dirichlet_prior: float = 0
212
+ ) -> CrossTable:
213
+ """
214
+ Generate a cross-table for the given random variables, using the given dataset, represented
215
+ as a dictionary, mapping instances to weights.
216
+
217
+ Args:
218
+ dataset: The dataset to use to compute the cross-table.
219
+ rvs: The random variables to compute the cross-table for. If omitted
220
+ then `dataset.rvs` will be used.
221
+ dirichlet_prior: a real number >= 0. See `CrossTable` for an explanation.
222
+
223
+ Returns:
224
+ The cross-table for the given random variables, using the given dataset,
225
+ represented as a dictionary mapping instances to weights.
226
+ An instance is a tuple of state indexes, co-indexed with rvs.
227
+
228
+ Raises:
229
+ KeyError: If any random variable in `rvs` does not appear in the dataset.
230
+ """
231
+ if rvs is None:
232
+ rvs = dataset.rvs
233
+
234
+ # Special case
235
+ if len(rvs) == 0:
236
+ return CrossTable((), 0, [((), dataset.total_weight() + dirichlet_prior)])
237
+
238
+ weights: CrossTable = CrossTable(rvs, dirichlet_prior)
239
+
240
+ columns: List[NDArray] = [
241
+ dataset.state_idxs(rv)
242
+ for rv in rvs
243
+ ]
244
+
245
+ for instance, weight in zip(zip(*columns), dataset.weights):
246
+ if weight != 0:
247
+ instance: Tuple[int, ...] = tuple(int(i) for i in instance)
248
+ weights.add(instance, weight)
249
+
250
+ return weights
251
+
252
+
253
+ def _product_instance_weights(instance_weights: Sequence[NDArray]) -> Iterator[Tuple[Tuple[int, ...], float]]:
254
+ """
255
+ Iterate over all possible instance for the given instance weights,
256
+ where the weight is not zero.
257
+ """
258
+
259
+ # Base case
260
+ if len(instance_weights) == 0:
261
+ yield (), 1
262
+
263
+ # Recursive case
264
+ else:
265
+ next_weights: NDArray = instance_weights[-1]
266
+ pre_weights: Sequence[NDArray] = instance_weights[:-1]
267
+ for pre_instance, pre_weight in _product_instance_weights(pre_weights):
268
+ for i, weight in enumerate(next_weights):
269
+ if weight != 0:
270
+ yield pre_instance + (int(i),), pre_weight * weight
@@ -0,0 +1,53 @@
1
+ from typing import Sequence, Tuple, Dict
2
+
3
+ from ck.dataset.cross_table import CrossTable, Instance
4
+ from ck.pgm import RandomVariable, Indicator
5
+ from ck.probability.probability_space import ProbabilitySpace, Condition, check_condition
6
+
7
+
8
+ class CrossTableProbabilitySpace(ProbabilitySpace):
9
+ def __init__(self, cross_table: CrossTable):
10
+ """
11
+ Enable probabilistic queries over a sample from a sample space.
12
+ Note that this is not necessarily an efficient approach to calculating probabilities and statistics.
13
+
14
+ Args:
15
+ cross_table: a CrossTable to adapt to a ProbabilitySpace.
16
+ """
17
+ self._cross_table: CrossTable = cross_table
18
+ self._rv_idx_to_sample_idx: Dict[int, int] = {
19
+ rv.idx: i
20
+ for i, rv in enumerate(cross_table.rvs)
21
+ }
22
+
23
+ @property
24
+ def rvs(self) -> Sequence[RandomVariable]:
25
+ return self._cross_table.rvs
26
+
27
+ def wmc(self, *condition: Condition) -> float:
28
+ condition: Tuple[Indicator, ...] = check_condition(condition)
29
+ rvs: Sequence[RandomVariable] = self._cross_table.rvs
30
+
31
+ checks = [set() for _ in rvs]
32
+ for ind in condition:
33
+ checks[self._rv_idx_to_sample_idx[ind.rv_idx]].add(ind.state_idx)
34
+ for i in range(len(checks)):
35
+ if len(checks[i]) > 0:
36
+ checks[i] = set(range(len(rvs[i]))).difference(checks[i])
37
+
38
+ def satisfied(item: Tuple[Instance, float]) -> float:
39
+ """
40
+ Return the weight of the instance, if the instance satisfies
41
+ the condition, else return 0.
42
+ """
43
+ instance, weight = item
44
+ if any((state in check) for state, check in zip(instance, checks)):
45
+ return 0
46
+ else:
47
+ return weight
48
+
49
+ return sum(map(satisfied, self._cross_table.items()))
50
+
51
+ @property
52
+ def z(self) -> float:
53
+ return self._cross_table.total_weight()