compiled-knowledge 4.0.0a25__cp313-cp313-win_amd64.whl → 4.1.0a2__cp313-cp313-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/_circuit_cy.c +1 -1
- ck/circuit/_circuit_cy.cp313-win_amd64.pyd +0 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.c +152 -152
- ck/circuit_compiler/cython_vm_compiler/_compiler.cp313-win_amd64.pyd +0 -0
- ck/circuit_compiler/interpret_compiler.py +2 -2
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.c +1 -1
- ck/circuit_compiler/support/circuit_analyser/_circuit_analyser_cy.cp313-win_amd64.pyd +0 -0
- ck/dataset/__init__.py +1 -0
- ck/dataset/cross_table.py +270 -0
- ck/dataset/cross_table_probabilities.py +53 -0
- ck/dataset/dataset.py +594 -0
- ck/dataset/dataset_builder.py +512 -0
- ck/dataset/dataset_compute.py +140 -0
- ck/dataset/dataset_from_crosstable.py +45 -0
- ck/dataset/dataset_from_csv.py +151 -0
- ck/dataset/sampled_dataset.py +96 -0
- ck/learning/__init__.py +0 -0
- ck/learning/train_generative.py +149 -0
- ck/pgm.py +29 -27
- ck/pgm_circuit/program_with_slotmap.py +23 -45
- ck/pgm_circuit/support/compile_circuit.py +2 -4
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy.c +1 -1
- ck/pgm_compiler/support/circuit_table/_circuit_table_cy.cp313-win_amd64.pyd +0 -0
- ck/probability/empirical_probability_space.py +1 -0
- ck_demos/dataset/__init__.py +0 -0
- ck_demos/dataset/demo_dataset_builder.py +37 -0
- {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/METADATA +1 -1
- {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/RECORD +31 -18
- {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/WHEEL +0 -0
- {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/licenses/LICENSE.txt +0 -0
- {compiled_knowledge-4.0.0a25.dist-info → compiled_knowledge-4.1.0a2.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
@@ -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
|
-
|
|
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-
|
|
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": [
|
|
Binary file
|
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()
|