compiled-knowledge 4.0.0a12__cp312-cp312-win_amd64.whl → 4.0.0a16__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/circuit.cp312-win_amd64.pyd +0 -0
- ck/circuit_compiler/cython_vm_compiler/_compiler.cp312-win_amd64.pyd +0 -0
- ck/circuit_compiler/named_circuit_compilers.py +8 -8
- ck/example/pathfinder.py +120 -47
- ck/in_out/parse_ace_lmap.py +1 -1
- ck/in_out/parse_ace_nnf.py +72 -38
- ck/in_out/parser_utils.py +1 -1
- ck/pgm_compiler/ace/ace.py +11 -8
- ck/pgm_compiler/factor_elimination.py +3 -3
- ck/pgm_compiler/named_pgm_compilers.py +26 -26
- ck/pgm_compiler/recursive_conditioning.py +1 -1
- ck/pgm_compiler/support/circuit_table/circuit_table.cp312-win_amd64.pyd +0 -0
- ck/pgm_compiler/support/factor_tables.py +34 -26
- ck/pgm_compiler/variable_elimination.py +1 -1
- ck/utils/local_config.py +270 -0
- ck_demos/ace/demo_ace.py +1 -1
- ck_demos/pgm_compiler/compare_pgm_compilers.py +15 -2
- ck_demos/utils/compare.py +50 -22
- {compiled_knowledge-4.0.0a12.dist-info → compiled_knowledge-4.0.0a16.dist-info}/METADATA +2 -2
- {compiled_knowledge-4.0.0a12.dist-info → compiled_knowledge-4.0.0a16.dist-info}/RECORD +23 -22
- {compiled_knowledge-4.0.0a12.dist-info → compiled_knowledge-4.0.0a16.dist-info}/WHEEL +0 -0
- {compiled_knowledge-4.0.0a12.dist-info → compiled_knowledge-4.0.0a16.dist-info}/licenses/LICENSE.txt +0 -0
- {compiled_knowledge-4.0.0a12.dist-info → compiled_knowledge-4.0.0a16.dist-info}/top_level.txt +0 -0
|
@@ -18,32 +18,32 @@ class NamedPGMCompiler(Enum):
|
|
|
18
18
|
"""
|
|
19
19
|
# @formatter:off
|
|
20
20
|
|
|
21
|
-
VE_MIN_DEGREE
|
|
22
|
-
VE_MIN_DEGREE_THEN_FILL
|
|
23
|
-
VE_MIN_FILL
|
|
24
|
-
VE_MIN_FILL_THEN_DEGREE
|
|
25
|
-
VE_MIN_WEIGHTED_DEGREE
|
|
26
|
-
VE_MIN_WEIGHTED_FILL
|
|
27
|
-
VE_MIN_TRADITIONAL_WEIGHTED_FILL
|
|
28
|
-
|
|
29
|
-
FE_MIN_DEGREE
|
|
30
|
-
FE_MIN_DEGREE_THEN_FILL
|
|
31
|
-
FE_MIN_FILL
|
|
32
|
-
FE_MIN_FILL_THEN_DEGREE
|
|
33
|
-
FE_MIN_WEIGHTED_DEGREE
|
|
34
|
-
FE_MIN_WEIGHTED_FILL
|
|
35
|
-
FE_MIN_TRADITIONAL_WEIGHTED_FILL
|
|
36
|
-
FE_BEST_JOINTREE
|
|
37
|
-
|
|
38
|
-
RC_MIN_DEGREE
|
|
39
|
-
RC_MIN_DEGREE_THEN_FILL
|
|
40
|
-
RC_MIN_FILL
|
|
41
|
-
RC_MIN_FILL_THEN_DEGREE
|
|
42
|
-
RC_MIN_WEIGHTED_DEGREE
|
|
43
|
-
RC_MIN_WEIGHTED_FILL
|
|
44
|
-
RC_MIN_TRADITIONAL_WEIGHTED_FILL
|
|
45
|
-
|
|
46
|
-
ACE
|
|
21
|
+
VE_MIN_DEGREE = _get_compiler_algorithm(variable_elimination, 'MIN_DEGREE')
|
|
22
|
+
VE_MIN_DEGREE_THEN_FILL = _get_compiler_algorithm(variable_elimination, 'MIN_DEGREE_THEN_FILL')
|
|
23
|
+
VE_MIN_FILL = _get_compiler_algorithm(variable_elimination, 'MIN_FILL')
|
|
24
|
+
VE_MIN_FILL_THEN_DEGREE = _get_compiler_algorithm(variable_elimination, 'MIN_FILL_THEN_DEGREE')
|
|
25
|
+
VE_MIN_WEIGHTED_DEGREE = _get_compiler_algorithm(variable_elimination, 'MIN_WEIGHTED_DEGREE')
|
|
26
|
+
VE_MIN_WEIGHTED_FILL = _get_compiler_algorithm(variable_elimination, 'MIN_WEIGHTED_FILL')
|
|
27
|
+
VE_MIN_TRADITIONAL_WEIGHTED_FILL = _get_compiler_algorithm(variable_elimination, 'MIN_TRADITIONAL_WEIGHTED_FILL')
|
|
28
|
+
|
|
29
|
+
FE_MIN_DEGREE = _get_compiler_algorithm(factor_elimination, 'MIN_DEGREE')
|
|
30
|
+
FE_MIN_DEGREE_THEN_FILL = _get_compiler_algorithm(factor_elimination, 'MIN_DEGREE_THEN_FILL')
|
|
31
|
+
FE_MIN_FILL = _get_compiler_algorithm(factor_elimination, 'MIN_FILL')
|
|
32
|
+
FE_MIN_FILL_THEN_DEGREE = _get_compiler_algorithm(factor_elimination, 'MIN_FILL_THEN_DEGREE')
|
|
33
|
+
FE_MIN_WEIGHTED_DEGREE = _get_compiler_algorithm(factor_elimination, 'MIN_WEIGHTED_DEGREE')
|
|
34
|
+
FE_MIN_WEIGHTED_FILL = _get_compiler_algorithm(factor_elimination, 'MIN_WEIGHTED_FILL')
|
|
35
|
+
FE_MIN_TRADITIONAL_WEIGHTED_FILL = _get_compiler_algorithm(factor_elimination, 'MIN_TRADITIONAL_WEIGHTED_FILL')
|
|
36
|
+
FE_BEST_JOINTREE = factor_elimination.compile_pgm_best_jointree,
|
|
37
|
+
|
|
38
|
+
RC_MIN_DEGREE = _get_compiler_algorithm(recursive_conditioning, 'MIN_DEGREE')
|
|
39
|
+
RC_MIN_DEGREE_THEN_FILL = _get_compiler_algorithm(recursive_conditioning, 'MIN_DEGREE_THEN_FILL')
|
|
40
|
+
RC_MIN_FILL = _get_compiler_algorithm(recursive_conditioning, 'MIN_FILL')
|
|
41
|
+
RC_MIN_FILL_THEN_DEGREE = _get_compiler_algorithm(recursive_conditioning, 'MIN_FILL_THEN_DEGREE')
|
|
42
|
+
RC_MIN_WEIGHTED_DEGREE = _get_compiler_algorithm(recursive_conditioning, 'MIN_WEIGHTED_DEGREE')
|
|
43
|
+
RC_MIN_WEIGHTED_FILL = _get_compiler_algorithm(recursive_conditioning, 'MIN_WEIGHTED_FILL')
|
|
44
|
+
RC_MIN_TRADITIONAL_WEIGHTED_FILL = _get_compiler_algorithm(recursive_conditioning, 'MIN_TRADITIONAL_WEIGHTED_FILL')
|
|
45
|
+
|
|
46
|
+
ACE = _get_compiler(ace)
|
|
47
47
|
|
|
48
48
|
# @formatter:on
|
|
49
49
|
|
|
@@ -28,7 +28,7 @@ def compile_pgm(
|
|
|
28
28
|
const_parameters: bool = True,
|
|
29
29
|
*,
|
|
30
30
|
algorithm: ClusterAlgorithm = MIN_FILL_THEN_DEGREE,
|
|
31
|
-
pre_prune_factor_tables: bool =
|
|
31
|
+
pre_prune_factor_tables: bool = False,
|
|
32
32
|
) -> PGMCircuit:
|
|
33
33
|
"""
|
|
34
34
|
Compile the PGM to an arithmetic circuit, using recursive conditioning.
|
|
Binary file
|
|
@@ -269,40 +269,48 @@ def _pre_prune_factor_tables(factor_rows: Sequence[_FactorRows]) -> None:
|
|
|
269
269
|
will be formed, which may eliminate rows. This method identifies and removes
|
|
270
270
|
such rows.
|
|
271
271
|
"""
|
|
272
|
+
# Find all pairs of factors that have at least one common random variable.
|
|
272
273
|
pairs_to_check: List[_FactorPair] = [
|
|
273
274
|
_FactorPair(f1, f2)
|
|
274
275
|
for f1, f2 in pairs(factor_rows)
|
|
275
276
|
if not set(f1.rv_indexes).isdisjoint(f1.rv_indexes)
|
|
276
277
|
]
|
|
277
278
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
while len(pairs_to_check) > 0:
|
|
281
|
-
pair = pairs_to_check.pop()
|
|
282
|
-
x = pair.x
|
|
283
|
-
y = pair.y
|
|
284
|
-
|
|
285
|
-
x_size = len(x)
|
|
286
|
-
y_size = len(y)
|
|
279
|
+
# Simple version.
|
|
280
|
+
for pair in pairs_to_check:
|
|
287
281
|
pair.prune()
|
|
288
282
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
283
|
+
# Earlier version.
|
|
284
|
+
# This version re-checks processed pairs that may get benefit from a subsequent pruning.
|
|
285
|
+
# Unfortunately, this is computationally expensive, and provides no practical benefit.
|
|
286
|
+
#
|
|
287
|
+
# pairs_done: List[_FactorPair] = []
|
|
288
|
+
# while len(pairs_to_check) > 0:
|
|
289
|
+
# pair: _FactorPair = pairs_to_check.pop()
|
|
290
|
+
# x: _FactorRows = pair.x
|
|
291
|
+
# y: _FactorRows = pair.y
|
|
292
|
+
#
|
|
293
|
+
# x_size = len(x)
|
|
294
|
+
# y_size = len(y)
|
|
295
|
+
# pair.prune()
|
|
296
|
+
#
|
|
297
|
+
# # See if any pairs need re-checking
|
|
298
|
+
# rvs_affected: Set[int] = set()
|
|
299
|
+
# if x_size != len(x):
|
|
300
|
+
# rvs_affected.update(x.rv_indexes)
|
|
301
|
+
# if y_size != len(y):
|
|
302
|
+
# rvs_affected.update(y.rv_indexes)
|
|
303
|
+
# if len(rvs_affected) > 0:
|
|
304
|
+
# next_pairs_done: List[_FactorPair] = []
|
|
305
|
+
# for pair in pairs_done:
|
|
306
|
+
# if rvs_affected.isdisjoint(pair.all_rv_indexes):
|
|
307
|
+
# next_pairs_done.append(pair)
|
|
308
|
+
# else:
|
|
309
|
+
# pairs_to_check.append(pair)
|
|
310
|
+
# pairs_done = next_pairs_done
|
|
311
|
+
#
|
|
312
|
+
# # Mark the current pair as done.
|
|
313
|
+
# pairs_done.append(pair)
|
|
306
314
|
|
|
307
315
|
|
|
308
316
|
def _make_factor_table(
|
|
@@ -25,7 +25,7 @@ def compile_pgm(
|
|
|
25
25
|
const_parameters: bool = True,
|
|
26
26
|
*,
|
|
27
27
|
algorithm: ClusterAlgorithm = MIN_FILL_THEN_DEGREE,
|
|
28
|
-
pre_prune_factor_tables: bool =
|
|
28
|
+
pre_prune_factor_tables: bool = False,
|
|
29
29
|
) -> PGMCircuit:
|
|
30
30
|
"""
|
|
31
31
|
Compile the PGM to an arithmetic circuit, using variable elimination.
|
ck/utils/local_config.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides access to local configuration variables.
|
|
3
|
+
|
|
4
|
+
Local configuration variables are {variable} = {value} pairs that
|
|
5
|
+
are defined externally to CK for the purposes of adapting
|
|
6
|
+
to the local environment that CK is installed in. Local
|
|
7
|
+
configuration variables are not expected to modify the
|
|
8
|
+
behaviour of algorithms implemented in CK.
|
|
9
|
+
|
|
10
|
+
The primary method to access local configuration is `get`. Various
|
|
11
|
+
other getter methods wrap `get`.
|
|
12
|
+
|
|
13
|
+
The `get` method will search for a value for a requested variable
|
|
14
|
+
using the following steps.
|
|
15
|
+
1) Check the `programmatic config` which is a dictionary that
|
|
16
|
+
can be directly updated.
|
|
17
|
+
2) Check the PYTHONPATH for a module called `config` (i.e., a
|
|
18
|
+
`config.py` file) for global variables defined in that module.
|
|
19
|
+
3) Check the system environment variables (`os.environ`).
|
|
20
|
+
|
|
21
|
+
Variable names must be a valid Python identifier. Only valid
|
|
22
|
+
value types are supported, as per the function `valid_value`.
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
from ck.utils.local_config import config
|
|
26
|
+
|
|
27
|
+
# assume `config.py` is in the PYTHONPATH and contains:
|
|
28
|
+
# ABC = 123
|
|
29
|
+
# DEF = 456
|
|
30
|
+
|
|
31
|
+
val = config.ABC # val = 123
|
|
32
|
+
val = config.XYZ # will raise an exception
|
|
33
|
+
val = config.get('ABC') # val = 123
|
|
34
|
+
val = config['DEF'] # val = 456
|
|
35
|
+
val = config['XYZ'] # will raise an exception
|
|
36
|
+
val = config.get('XYZ') # val = None
|
|
37
|
+
val = config.get('XYZ', 999) # val = 999
|
|
38
|
+
|
|
39
|
+
from ck.utils.local_config import get_params
|
|
40
|
+
|
|
41
|
+
val = get_params('ABC') # val = ('ABC', 123)
|
|
42
|
+
val = get_params('ABC', 'DEF') # val = (('ABC', 123), ('DEF', 456))
|
|
43
|
+
val = get_params('ABC', 'DEF', sep='=') # val = ('ABC=123', 'DEF=456')
|
|
44
|
+
val = get_params('ABC;DEF', delim=';') # val = 'ABC=123;DEF=456'
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
import inspect
|
|
49
|
+
import os
|
|
50
|
+
from ast import literal_eval
|
|
51
|
+
from itertools import chain
|
|
52
|
+
from typing import Optional, Dict, Any, Sequence, Iterable
|
|
53
|
+
|
|
54
|
+
from ck.utils.iter_extras import flatten
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
# Try to import the user's `config.py`
|
|
58
|
+
import config as _user_config
|
|
59
|
+
except ImportError:
|
|
60
|
+
_user_config = None
|
|
61
|
+
|
|
62
|
+
# Sentinel object
|
|
63
|
+
_NIL = object()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class Config:
|
|
67
|
+
|
|
68
|
+
def __init__(self):
|
|
69
|
+
self._programmatic_config: Dict[str, Any] = {}
|
|
70
|
+
|
|
71
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
72
|
+
"""
|
|
73
|
+
Get the value of the given local configuration variable.
|
|
74
|
+
If the configuration variable is not available, return the given default value.
|
|
75
|
+
"""
|
|
76
|
+
if not key.isidentifier():
|
|
77
|
+
raise KeyError(f'invalid local configuration parameter: {key!r}')
|
|
78
|
+
|
|
79
|
+
# Check the programmatic config
|
|
80
|
+
value = self._programmatic_config.get(key, _NIL)
|
|
81
|
+
if value is not _NIL:
|
|
82
|
+
return value
|
|
83
|
+
|
|
84
|
+
# Check config.py
|
|
85
|
+
if _user_config is not None:
|
|
86
|
+
value = vars(_user_config).get(key, _NIL)
|
|
87
|
+
if value is not _NIL:
|
|
88
|
+
if not valid_value(value):
|
|
89
|
+
raise KeyError(f'user configuration file contains an invalid value for variable: {key!r}')
|
|
90
|
+
return value
|
|
91
|
+
|
|
92
|
+
# Check the OS environment
|
|
93
|
+
value = os.environ.get(key, _NIL)
|
|
94
|
+
if value is not _NIL:
|
|
95
|
+
return value
|
|
96
|
+
|
|
97
|
+
# Not found - return the default value
|
|
98
|
+
return default
|
|
99
|
+
|
|
100
|
+
def __contains__(self, key: str) -> bool:
|
|
101
|
+
return self.get(key, _NIL) is not _NIL
|
|
102
|
+
|
|
103
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
104
|
+
"""
|
|
105
|
+
Programmatically overwrite a local configuration variable.
|
|
106
|
+
"""
|
|
107
|
+
if not key.isidentifier():
|
|
108
|
+
raise KeyError(f'invalid local configuration parameter: {key!r}')
|
|
109
|
+
if not valid_value(value):
|
|
110
|
+
raise ValueError(f'invalid local configuration parameter value: {value!r}')
|
|
111
|
+
self._programmatic_config[key] = value
|
|
112
|
+
|
|
113
|
+
def __getitem__(self, key: str):
|
|
114
|
+
"""
|
|
115
|
+
Get the value of the given configuration variable.
|
|
116
|
+
If the configuration variable is not available, raise a KeyError.
|
|
117
|
+
"""
|
|
118
|
+
value = self.get(key, _NIL)
|
|
119
|
+
if value is _NIL:
|
|
120
|
+
raise KeyError(f'undefined local configuration parameter: {key}')
|
|
121
|
+
return value
|
|
122
|
+
|
|
123
|
+
def __getattr__(self, key: str):
|
|
124
|
+
"""
|
|
125
|
+
Get the value of the given configuration variable.
|
|
126
|
+
If the configuration variable is not available, raise a KeyError.
|
|
127
|
+
"""
|
|
128
|
+
value = self.get(key, _NIL)
|
|
129
|
+
if value is _NIL:
|
|
130
|
+
raise KeyError(f'undefined local configuration parameter: {key}')
|
|
131
|
+
return value
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# The global local config object.
|
|
135
|
+
config = Config()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def valid_value(value: Any) -> bool:
|
|
139
|
+
"""
|
|
140
|
+
Does the given value have an acceptable type for
|
|
141
|
+
a configuration variable?
|
|
142
|
+
"""
|
|
143
|
+
if isinstance(value, (list, tuple, set)):
|
|
144
|
+
return all(valid_value(elem) for elem in value)
|
|
145
|
+
if isinstance(value, dict):
|
|
146
|
+
return all(valid_value(elem) for elem in chain(value.keys(), value.values()))
|
|
147
|
+
if callable(value) or inspect.isfunction(value) or inspect.ismodule(value):
|
|
148
|
+
return False
|
|
149
|
+
# All tests pass
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# noinspection PyShadowingNames
|
|
154
|
+
def get_params(
|
|
155
|
+
*keys: str,
|
|
156
|
+
sep: Optional[str] = None,
|
|
157
|
+
delim: Optional[str] = None,
|
|
158
|
+
config: Config = config,
|
|
159
|
+
):
|
|
160
|
+
"""
|
|
161
|
+
Return one or more configuration parameter as key-value pairs.
|
|
162
|
+
|
|
163
|
+
If `sep` is None then each key-value pair is returned as a tuple, otherwise
|
|
164
|
+
each key-value pair is returned as a string with `sep` as the separator.
|
|
165
|
+
|
|
166
|
+
If `delim` is None then each key is treated as is. If one key is provided then
|
|
167
|
+
its value is returned. If multiple keys are provided, then multiple values
|
|
168
|
+
are returned in a tuple.
|
|
169
|
+
|
|
170
|
+
If `delim` is not None, then keys are split using `delim`, and results
|
|
171
|
+
are returned as a single string with `delim` as the delimiter. If
|
|
172
|
+
`delim` is not None then the default value for `sep` is '='.
|
|
173
|
+
|
|
174
|
+
For example, assume config.py contains: ABC = 123 and DEF = 456,
|
|
175
|
+
then:
|
|
176
|
+
get_params('ABC') -> ('ABC', 123)
|
|
177
|
+
get_params('ABC', 'DEF') -> ('ABC', 123), ('DEF', 456)
|
|
178
|
+
get_params('ABC', sep='=') = 'ABC=123'
|
|
179
|
+
get_params('ABC', 'DEF', sep='=') = 'ABC=123', 'DEF=456'
|
|
180
|
+
get_params('ABC;DEF', delim=';') = 'ABC=123;DEF=456'
|
|
181
|
+
get_params('ABC;DEF', sep='==', delim=';') = 'ABC==123;DEF==456'
|
|
182
|
+
|
|
183
|
+
:param keys: the names of variables to access.
|
|
184
|
+
:param sep: the separator character between {variable} and {value}.
|
|
185
|
+
:param delim: the delimiter character between key-value pairs.
|
|
186
|
+
:param config: a Config instance to update. Default is the global config.
|
|
187
|
+
"""
|
|
188
|
+
if delim is not None:
|
|
189
|
+
keys = flatten(key.split(delim) for key in keys)
|
|
190
|
+
if sep is None:
|
|
191
|
+
sep = '='
|
|
192
|
+
|
|
193
|
+
if sep is None:
|
|
194
|
+
items = ((key, config[key]) for key in keys)
|
|
195
|
+
else:
|
|
196
|
+
items = (f'{key}{sep}{config[key]!r}' for key in keys)
|
|
197
|
+
|
|
198
|
+
if delim is None:
|
|
199
|
+
result = tuple(items)
|
|
200
|
+
if len(result) == 1:
|
|
201
|
+
result = result[0]
|
|
202
|
+
else:
|
|
203
|
+
result = delim.join(str(item) for item in items)
|
|
204
|
+
|
|
205
|
+
return result
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# noinspection PyShadowingNames
|
|
209
|
+
def update_config(
|
|
210
|
+
argv: Sequence[str],
|
|
211
|
+
valid_keys: Optional[Iterable[str]] = None,
|
|
212
|
+
*,
|
|
213
|
+
sep: str = '=',
|
|
214
|
+
strip_whitespace: bool = True,
|
|
215
|
+
config: Config = config,
|
|
216
|
+
) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Programmatically overwrite a local configuration variable from a command line `argv`.
|
|
219
|
+
|
|
220
|
+
Variable values are interpreted as per a Python literal.
|
|
221
|
+
|
|
222
|
+
Example usage:
|
|
223
|
+
import sys
|
|
224
|
+
from ck.utils.local_config import update_config
|
|
225
|
+
|
|
226
|
+
def main():
|
|
227
|
+
...
|
|
228
|
+
|
|
229
|
+
if __name__ == '__main__':
|
|
230
|
+
update_config(sys.argv, ['in_name', 'out_name'])
|
|
231
|
+
main()
|
|
232
|
+
|
|
233
|
+
:param argv: a collection of strings in the form '{variable}={value}'.
|
|
234
|
+
Variables not in `valid_keys` will raise a ValueError.
|
|
235
|
+
:param valid_keys: an optional collection of strings that are valid variables to
|
|
236
|
+
process from argv, or None to accept all variables.
|
|
237
|
+
:param sep: the separator character between {variable} and {value}.
|
|
238
|
+
Defaults is '='.
|
|
239
|
+
:param strip_whitespace: If True, then whitespace is stripped from
|
|
240
|
+
the value before updating the config. Whitespace is always stripped
|
|
241
|
+
from the variable name.
|
|
242
|
+
:param config: a Config instance to update. Default is the global config.
|
|
243
|
+
"""
|
|
244
|
+
if valid_keys is not None:
|
|
245
|
+
valid_keys = set(valid_keys)
|
|
246
|
+
|
|
247
|
+
for arg in argv:
|
|
248
|
+
var_val = str(arg).split(sep, maxsplit=1)
|
|
249
|
+
if len(var_val) != 2:
|
|
250
|
+
raise ValueError(f'cannot split argument: {arg!r} using separator {sep!r}')
|
|
251
|
+
|
|
252
|
+
var, val = var_val
|
|
253
|
+
var = var.strip()
|
|
254
|
+
if strip_whitespace:
|
|
255
|
+
val = val.strip()
|
|
256
|
+
|
|
257
|
+
if valid_keys is not None and var not in valid_keys:
|
|
258
|
+
raise KeyError(f'invalid key: {arg!r}')
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
interpreted = literal_eval(val)
|
|
262
|
+
except (ValueError, SyntaxError) as err:
|
|
263
|
+
# Some operating systems strip quotes off
|
|
264
|
+
# strings, so we try to recover.
|
|
265
|
+
if '"' in val or "'" in val:
|
|
266
|
+
# Too hard... forget it.
|
|
267
|
+
raise err
|
|
268
|
+
interpreted = str(val)
|
|
269
|
+
|
|
270
|
+
config[var] = interpreted
|
ck_demos/ace/demo_ace.py
CHANGED
|
@@ -17,7 +17,7 @@ def main() -> None:
|
|
|
17
17
|
# Here is an example showing how to copy Ace to the default
|
|
18
18
|
# location from a source directory.
|
|
19
19
|
#
|
|
20
|
-
# ace.copy_ace_to_default_location(r'
|
|
20
|
+
# ace.copy_ace_to_default_location(r'C:\Research\Ace\ace_v3.0_windows')
|
|
21
21
|
|
|
22
22
|
pgm_cct: PGMCircuit = ace.compile_pgm(pgm, print_output=True)
|
|
23
23
|
|
|
@@ -9,6 +9,15 @@ from ck_demos.utils.compare import compare
|
|
|
9
9
|
|
|
10
10
|
# @formatter:off
|
|
11
11
|
|
|
12
|
+
# =========================================
|
|
13
|
+
# Experiment configuration
|
|
14
|
+
# =========================================
|
|
15
|
+
|
|
16
|
+
CACHE_CIRCUITS: bool = True
|
|
17
|
+
BREAK_BETWEEN_PGMS: bool = True
|
|
18
|
+
COMMA_NUMBERS: bool = True
|
|
19
|
+
PRINT_HEADER: bool = True
|
|
20
|
+
|
|
12
21
|
PGMS: Sequence[PGM] = [
|
|
13
22
|
example.Rain(),
|
|
14
23
|
example.Cancer(),
|
|
@@ -25,14 +34,14 @@ PGMS: Sequence[PGM] = [
|
|
|
25
34
|
# example.Mildew(),
|
|
26
35
|
]
|
|
27
36
|
|
|
28
|
-
CCT_COMPILERS: Sequence[NamedCircuitCompiler] = [DEFAULT_CIRCUIT_COMPILER]
|
|
29
|
-
|
|
30
37
|
PGM_COMPILERS: Sequence[NamedPGMCompiler] = [
|
|
31
38
|
named_compiler
|
|
32
39
|
for named_compiler in NamedPGMCompiler
|
|
33
40
|
if named_compiler.name.startswith('FE_') and 'WEIGHTED' not in named_compiler.name
|
|
34
41
|
] + [NamedPGMCompiler.ACE]
|
|
35
42
|
|
|
43
|
+
CCT_COMPILERS: Sequence[NamedCircuitCompiler] = [DEFAULT_CIRCUIT_COMPILER]
|
|
44
|
+
|
|
36
45
|
# @formatter:on
|
|
37
46
|
|
|
38
47
|
|
|
@@ -41,6 +50,10 @@ def main() -> None:
|
|
|
41
50
|
pgms=PGMS,
|
|
42
51
|
pgm_compilers=PGM_COMPILERS,
|
|
43
52
|
cct_compilers=CCT_COMPILERS,
|
|
53
|
+
cache_circuits=CACHE_CIRCUITS,
|
|
54
|
+
break_between_pgms=BREAK_BETWEEN_PGMS,
|
|
55
|
+
comma_numbers=COMMA_NUMBERS,
|
|
56
|
+
print_header=PRINT_HEADER,
|
|
44
57
|
)
|
|
45
58
|
print()
|
|
46
59
|
print('Done.')
|
ck_demos/utils/compare.py
CHANGED
|
@@ -7,13 +7,17 @@ from ck.pgm_circuit.wmc_program import WMCProgram
|
|
|
7
7
|
from ck.pgm_compiler import NamedPGMCompiler
|
|
8
8
|
from ck_demos.utils.stop_watch import StopWatch
|
|
9
9
|
|
|
10
|
-
CACHE_CIRCUIT: bool = True
|
|
11
|
-
|
|
12
10
|
|
|
13
11
|
def compare(
|
|
14
12
|
pgms: Sequence[PGM],
|
|
15
13
|
pgm_compilers: Sequence[NamedPGMCompiler],
|
|
16
14
|
cct_compilers: Sequence[NamedCircuitCompiler],
|
|
15
|
+
*,
|
|
16
|
+
cache_circuits: bool = True,
|
|
17
|
+
break_between_pgms: bool = True,
|
|
18
|
+
comma_numbers: bool = True,
|
|
19
|
+
print_header: bool = True,
|
|
20
|
+
sep: str = ' ',
|
|
17
21
|
) -> None:
|
|
18
22
|
"""
|
|
19
23
|
For each combination of the given arguments, construct a PGMCircuit (using a
|
|
@@ -35,54 +39,78 @@ def compare(
|
|
|
35
39
|
pgms: a sequence of PGM objects.
|
|
36
40
|
pgm_compilers: a sequence of named PGM compilers.
|
|
37
41
|
cct_compilers: a sequence of named circuit compilers.
|
|
42
|
+
cache_circuits: if true, then circuits are reused across different circuit compilers.
|
|
43
|
+
break_between_pgms: if true, print a blank line between different workload PGMs.
|
|
44
|
+
comma_numbers: if true, commas are used in large numbers.
|
|
45
|
+
print_header: if true, a header line is printed.
|
|
46
|
+
sep: column separator.
|
|
38
47
|
"""
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
# Work out column widths for names.
|
|
49
|
+
col_pgm_name: int = max(3, max(len(pgm.name) for pgm in pgms))
|
|
50
|
+
col_pgm_compiler_name: int = max(12, max(len(pgm_compiler.name) for pgm_compiler in pgm_compilers))
|
|
51
|
+
col_cct_compiler_name: int = max(12, max(len(cct_compiler.name) for cct_compiler in cct_compilers))
|
|
52
|
+
col_cct_ops: int = 10
|
|
53
|
+
col_pgm_compile_time: int = 16
|
|
54
|
+
col_cct_compile_time: int = 16
|
|
55
|
+
col_execute_time: int = 10
|
|
56
|
+
|
|
57
|
+
# Print formatting
|
|
58
|
+
comma: str = ',' if comma_numbers else ''
|
|
43
59
|
|
|
44
|
-
|
|
60
|
+
if print_header:
|
|
61
|
+
print('PGM'.ljust(col_pgm_name), end=sep)
|
|
62
|
+
print('PGM-compiler'.ljust(col_pgm_compiler_name), end=sep)
|
|
63
|
+
print('CCT-compiler'.ljust(col_cct_compiler_name), end=sep)
|
|
64
|
+
print('CCT-ops'.rjust(col_cct_ops), end=sep)
|
|
65
|
+
print('PGM-compile-time'.rjust(col_pgm_compile_time), end=sep)
|
|
66
|
+
print('CCT-compile-time'.rjust(col_cct_compile_time), end=sep)
|
|
67
|
+
print('Run-time'.rjust(col_execute_time))
|
|
68
|
+
|
|
69
|
+
# Variables for when cache_circuits is true
|
|
45
70
|
prev_pgm = None
|
|
46
71
|
prev_pgm_compiler = None
|
|
47
72
|
|
|
48
73
|
for pgm in pgms:
|
|
49
|
-
pgm_name: str = pgm.name.ljust(
|
|
74
|
+
pgm_name: str = pgm.name.ljust(col_pgm_name)
|
|
50
75
|
for pgm_compiler in pgm_compilers:
|
|
51
|
-
pgm_compiler_name: str = pgm_compiler.name.ljust(
|
|
76
|
+
pgm_compiler_name: str = pgm_compiler.name.ljust(col_pgm_compiler_name)
|
|
52
77
|
for cct_compiler in cct_compilers:
|
|
53
|
-
cct_compiler_name: str = cct_compiler.name.ljust(
|
|
78
|
+
cct_compiler_name: str = cct_compiler.name.ljust(col_cct_compiler_name)
|
|
54
79
|
|
|
55
|
-
print(
|
|
56
|
-
print(
|
|
57
|
-
print(
|
|
80
|
+
print(pgm_name, end=sep)
|
|
81
|
+
print(pgm_compiler_name, end=sep)
|
|
82
|
+
print(cct_compiler_name, end=sep)
|
|
58
83
|
|
|
59
84
|
try:
|
|
60
85
|
time = StopWatch()
|
|
61
86
|
|
|
62
|
-
if
|
|
63
|
-
print(f'{"":
|
|
64
|
-
print(f'{"":
|
|
87
|
+
if cache_circuits and pgm is prev_pgm and pgm_compiler is prev_pgm_compiler:
|
|
88
|
+
print(f'{"":{col_cct_ops}}', end=sep)
|
|
89
|
+
print(f'{"":{col_pgm_compile_time}}', end=sep)
|
|
65
90
|
else:
|
|
66
91
|
time.start()
|
|
67
92
|
pgm_cct: PGMCircuit = pgm_compiler(pgm)
|
|
68
93
|
time.stop()
|
|
69
|
-
|
|
70
|
-
print(f'{
|
|
94
|
+
num_ops: int = pgm_cct.circuit_top.circuit.number_of_operations
|
|
95
|
+
print(f'{num_ops:{col_cct_ops}{comma}}', end=sep)
|
|
96
|
+
print(f'{time.seconds():{col_pgm_compile_time}{comma}.3f}', end=sep)
|
|
71
97
|
prev_pgm = pgm
|
|
72
98
|
prev_pgm_compiler = pgm_compiler
|
|
73
99
|
|
|
74
100
|
time.start()
|
|
101
|
+
# `pgm_cct` will always be set but the IDE can't work that out.
|
|
102
|
+
# noinspection PyUnboundLocalVariable
|
|
75
103
|
wmc = WMCProgram(pgm_cct, compiler=cct_compiler.compiler)
|
|
76
104
|
time.stop()
|
|
77
|
-
print(f'{time.seconds():
|
|
105
|
+
print(f'{time.seconds():{col_cct_compile_time}{comma}.3f}', end=sep)
|
|
78
106
|
|
|
79
107
|
time.start()
|
|
80
108
|
for _ in range(1000):
|
|
81
109
|
wmc.compute()
|
|
82
110
|
time.stop()
|
|
83
|
-
print(f'{time.seconds() * 1000:
|
|
111
|
+
print(f'{time.seconds() * 1000:{col_execute_time}{comma}.3f}', end=sep)
|
|
84
112
|
except Exception as err:
|
|
85
113
|
print(repr(err), end='')
|
|
86
|
-
|
|
87
114
|
print()
|
|
88
|
-
|
|
115
|
+
if break_between_pgms:
|
|
116
|
+
print()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compiled-knowledge
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.0a16
|
|
4
4
|
Summary: A Python package for compiling and querying discrete probabilistic graphical models.
|
|
5
5
|
Author-email: Barry Drake <barry@compiledknowledge.org>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -43,7 +43,7 @@ Refer to the project online documentation at
|
|
|
43
43
|
The primary repository for the project is
|
|
44
44
|
[github.com/ropeless/compiled_knowledge](https://github.com/ropeless/compiled_knowledge).
|
|
45
45
|
|
|
46
|
-
The Python package is available on
|
|
46
|
+
The Python package is available on PyPI, see
|
|
47
47
|
[pypi.org/project/compiled-knowledge](https://pypi.org/project/compiled-knowledge/).
|
|
48
48
|
|
|
49
49
|
For more information email
|