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.

@@ -18,32 +18,32 @@ class NamedPGMCompiler(Enum):
18
18
  """
19
19
  # @formatter:off
20
20
 
21
- VE_MIN_DEGREE: PGMCompiler = _get_compiler_algorithm(variable_elimination, 'MIN_DEGREE')
22
- VE_MIN_DEGREE_THEN_FILL: PGMCompiler = _get_compiler_algorithm(variable_elimination, 'MIN_DEGREE_THEN_FILL')
23
- VE_MIN_FILL: PGMCompiler = _get_compiler_algorithm(variable_elimination, 'MIN_FILL')
24
- VE_MIN_FILL_THEN_DEGREE: PGMCompiler = _get_compiler_algorithm(variable_elimination, 'MIN_FILL_THEN_DEGREE')
25
- VE_MIN_WEIGHTED_DEGREE: PGMCompiler = _get_compiler_algorithm(variable_elimination, 'MIN_WEIGHTED_DEGREE')
26
- VE_MIN_WEIGHTED_FILL: PGMCompiler = _get_compiler_algorithm(variable_elimination, 'MIN_WEIGHTED_FILL')
27
- VE_MIN_TRADITIONAL_WEIGHTED_FILL: PGMCompiler = _get_compiler_algorithm(variable_elimination, 'MIN_TRADITIONAL_WEIGHTED_FILL')
28
-
29
- FE_MIN_DEGREE: PGMCompiler = _get_compiler_algorithm(factor_elimination, 'MIN_DEGREE')
30
- FE_MIN_DEGREE_THEN_FILL: PGMCompiler = _get_compiler_algorithm(factor_elimination, 'MIN_DEGREE_THEN_FILL')
31
- FE_MIN_FILL: PGMCompiler = _get_compiler_algorithm(factor_elimination, 'MIN_FILL')
32
- FE_MIN_FILL_THEN_DEGREE: PGMCompiler = _get_compiler_algorithm(factor_elimination, 'MIN_FILL_THEN_DEGREE')
33
- FE_MIN_WEIGHTED_DEGREE: PGMCompiler = _get_compiler_algorithm(factor_elimination, 'MIN_WEIGHTED_DEGREE')
34
- FE_MIN_WEIGHTED_FILL: PGMCompiler = _get_compiler_algorithm(factor_elimination, 'MIN_WEIGHTED_FILL')
35
- FE_MIN_TRADITIONAL_WEIGHTED_FILL: PGMCompiler = _get_compiler_algorithm(factor_elimination, 'MIN_TRADITIONAL_WEIGHTED_FILL')
36
- FE_BEST_JOINTREE: PGMCompiler = factor_elimination.compile_pgm_best_jointree,
37
-
38
- RC_MIN_DEGREE: PGMCompiler = _get_compiler_algorithm(recursive_conditioning, 'MIN_DEGREE')
39
- RC_MIN_DEGREE_THEN_FILL: PGMCompiler = _get_compiler_algorithm(recursive_conditioning, 'MIN_DEGREE_THEN_FILL')
40
- RC_MIN_FILL: PGMCompiler = _get_compiler_algorithm(recursive_conditioning, 'MIN_FILL')
41
- RC_MIN_FILL_THEN_DEGREE: PGMCompiler = _get_compiler_algorithm(recursive_conditioning, 'MIN_FILL_THEN_DEGREE')
42
- RC_MIN_WEIGHTED_DEGREE: PGMCompiler = _get_compiler_algorithm(recursive_conditioning, 'MIN_WEIGHTED_DEGREE')
43
- RC_MIN_WEIGHTED_FILL: PGMCompiler = _get_compiler_algorithm(recursive_conditioning, 'MIN_WEIGHTED_FILL')
44
- RC_MIN_TRADITIONAL_WEIGHTED_FILL: PGMCompiler = _get_compiler_algorithm(recursive_conditioning, 'MIN_TRADITIONAL_WEIGHTED_FILL')
45
-
46
- ACE: PGMCompiler = _get_compiler(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 = True,
31
+ pre_prune_factor_tables: bool = False,
32
32
  ) -> PGMCircuit:
33
33
  """
34
34
  Compile the PGM to an arithmetic circuit, using recursive conditioning.
@@ -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
- pairs_done: List[_FactorPair] = []
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
- # See if any pairs need re-checking
290
- rvs_affected: Set[int] = set()
291
- if x_size != len(x):
292
- rvs_affected.update(x.rv_indexes)
293
- if y_size != len(y):
294
- rvs_affected.update(y.rv_indexes)
295
- if len(rvs_affected) > 0:
296
- next_pairs_done: List[_FactorPair] = []
297
- for pair in pairs_done:
298
- if rvs_affected.isdisjoint(pair.all_rv_indexes):
299
- next_pairs_done.append(pair)
300
- else:
301
- pairs_to_check.append(pair)
302
- pairs_done = next_pairs_done
303
-
304
- # Mark the current pair as done.
305
- pairs_done.append(pair)
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 = True,
28
+ pre_prune_factor_tables: bool = False,
29
29
  ) -> PGMCircuit:
30
30
  """
31
31
  Compile the PGM to an arithmetic circuit, using variable elimination.
@@ -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'E:\Dropbox\Research\Ace\all')
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
- # work out column widths for names.
40
- max_pgm_name: int = max(len(pgm.name) for pgm in pgms)
41
- max_pgm_compiler_name: int = max(len(pgm_compiler.name) for pgm_compiler in pgm_compilers)
42
- max_cct_compiler_name: int = max(len(cct_compiler.name) for cct_compiler in cct_compilers)
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
- # variables for when CACHE_CIRCUIT is true
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(max_pgm_name)
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(max_pgm_compiler_name)
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(max_cct_compiler_name)
78
+ cct_compiler_name: str = cct_compiler.name.ljust(col_cct_compiler_name)
54
79
 
55
- print(f'{pgm_name} ', end='')
56
- print(f'{pgm_compiler_name} ', end='')
57
- print(f'{cct_compiler_name} ', end='')
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 CACHE_CIRCUIT and pgm is prev_pgm and pgm_compiler is prev_pgm_compiler:
63
- print(f'{"":10} ', end='')
64
- print(f'{"":10} ', end='')
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
- print(f'{pgm_cct.circuit_top.circuit.number_of_operations:10,} ', end='')
70
- print(f'{time.seconds():10.3f}s ', end='')
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():10.3f}s ', end='')
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:10.3f}μs ', end='')
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
- print()
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.0a12
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 PyPi, see
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