compiled-knowledge 4.0.0a15__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.

Binary file
@@ -1,11 +1,12 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import Tuple, Optional, Dict, List
2
+ from typing import Tuple, Optional, Dict, List, Sequence
3
3
 
4
4
  import numpy as np
5
5
 
6
6
  from ck.circuit import Circuit, CircuitNode, VarNode, ConstValue, ConstNode
7
7
  from ck.in_out.parse_ace_lmap import LiteralMap
8
8
  from ck.in_out.parser_utils import ParseError, ParserInput
9
+ from ck.pgm import Indicator
9
10
  from ck.pgm_circuit.slot_map import SlotKey, SlotMap
10
11
  from ck.utils.np_extras import NDArrayFloat64
11
12
 
@@ -18,9 +19,9 @@ def read_nnf_with_literal_map(
18
19
  input_stream,
19
20
  literal_map: LiteralMap,
20
21
  *,
22
+ indicators: Sequence[Indicator] = (),
21
23
  const_parameters: bool = True,
22
24
  optimise_ops: bool = True,
23
- circuit: Optional[Circuit] = None,
24
25
  check_header: bool = False,
25
26
  ) -> Tuple[CircuitNode, SlotMap, NDArrayFloat64]:
26
27
  """
@@ -31,8 +32,8 @@ def read_nnf_with_literal_map(
31
32
 
32
33
  Args:
33
34
  input_stream: to parse, as per `ParserInput` argument.
35
+ indicators: any indicators to pre allocate to circuit variables.
34
36
  literal_map: mapping from literal code to indicators.
35
- circuit: an optional circuit to reuse.
36
37
  check_header: if true, an exception is raised if the number of nodes or arcs is not as expected.
37
38
  const_parameters: if true, the potential function parameters will be circuit
38
39
  constants, otherwise they will be circuit variables.
@@ -44,6 +45,7 @@ def read_nnf_with_literal_map(
44
45
  slot_map: is a map from indicator to a circuit var index (int).
45
46
  params: is a numpy array of parameter values, co-indexed with `circuit.vars[num_indicators:]`
46
47
  """
48
+ circuit = Circuit()
47
49
 
48
50
  # Set the `const_literals` parameter for `read_nnf`
49
51
  const_literals: Optional[Dict[int, ConstValue]]
@@ -57,38 +59,42 @@ def read_nnf_with_literal_map(
57
59
  else:
58
60
  const_literals = {}
59
61
 
60
- top_node, literal_slot_map = read_nnf(
62
+ # Make a slot map to map from an indicator to a circuit variable index.
63
+ # Preload `var_literals` to map literal codes to circuit vars.
64
+ # We allocate the circuit variables here to ensure that indicators
65
+ # come before parameters in the circuit variables.
66
+ slot_map: Dict[SlotKey, int] = {
67
+ indicator: i
68
+ for i, indicator in enumerate(indicators)
69
+ }
70
+ circuit.new_vars(len(slot_map))
71
+ var_literals: Dict[int, int] = {}
72
+ for literal_code, indicator in literal_map.indicators.items():
73
+ slot = slot_map.get(indicator)
74
+ if slot is None:
75
+ slot = circuit.new_var().idx
76
+ slot_map[indicator] = slot
77
+ var_literals[literal_code] = slot
78
+ num_indicators: int = len(slot_map)
79
+
80
+ # Parse the nnf file
81
+ top_node, vars_literals = read_nnf(
61
82
  input_stream,
83
+ var_literals=var_literals,
62
84
  const_literals=const_literals,
63
85
  circuit=circuit,
64
86
  check_header=check_header,
65
87
  optimise_ops=optimise_ops,
66
88
  )
67
- circuit = top_node.circuit
68
-
69
- # Build the slot map from indicator to slot.
70
- # Some indicators may not be in `literal_slot_map` because they were not needed
71
- # for the arithmetic circuit in the NNF file. For those indicators, we create
72
- # dummy circuit vars.
73
- def _get_slot(_literal_code: int) -> int:
74
- _slot: Optional[int] = literal_slot_map.get(_literal_code)
75
- if _slot is None:
76
- _slot: int = circuit.new_var().idx
77
- return _slot
78
89
 
79
- slot_map: Dict[SlotKey, int] = {
80
- indicator: _get_slot(literal_code)
81
- for literal_code, indicator in literal_map.indicators.items()
82
- }
83
-
84
- # Get the parameter values
85
- num_indicators: int = len(literal_map.indicators)
90
+ # Get the parameter values.
91
+ # Any new circuit vars added to the circuit are parameters.
92
+ # Parameter IDs are not added to the slot map as we don't know them.
86
93
  num_parameters: int = top_node.circuit.number_of_vars - num_indicators
87
94
  assert num_parameters == 0 or not const_parameters, 'const_parameters -> num_parameters == 0'
88
-
89
95
  params: NDArrayFloat64 = np.zeros(num_parameters, dtype=np.float64)
90
96
  for literal_code, value in literal_map.params.items():
91
- literal_slot: Optional[int] = literal_slot_map.get(literal_code)
97
+ literal_slot: Optional[int] = var_literals.get(literal_code)
92
98
  if literal_slot is not None and literal_slot >= num_indicators:
93
99
  params[literal_slot - num_indicators] = value
94
100
 
@@ -98,6 +104,7 @@ def read_nnf_with_literal_map(
98
104
  def read_nnf(
99
105
  input_stream,
100
106
  *,
107
+ var_literals: Optional[Dict[int, int]] = None,
101
108
  const_literals: Optional[Dict[int, ConstValue]] = None,
102
109
  circuit: Optional[Circuit] = None,
103
110
  check_header: bool = False,
@@ -109,44 +116,51 @@ def read_nnf(
109
116
  The input consists of propositional logical sentences in negative normal form (NNF).
110
117
  This covers both ".ac" and ".nnf" files produced by the software ACE.
111
118
 
112
- The returned slot map will have entries to get circuit vars for literal codes.
113
- E.g., given a literal code (int), use `circuit.vars[slot_map[literal_code]]` to get its var node.
119
+ This function returns the last node parsed (or the constant zero node if no nodes passed).
120
+ It also returns a mapping from literal code (int) to circuit variable index.
114
121
 
115
- Software may simplify an NNF file by removing arcs, but it may not update the header.
116
- Although the resulting file is not conformant, it is still parsable.
117
- Parameter `check_header` can be set to false, which prevents an exception being raised.
122
+ Two optional dictionaries may be supplied. Dictionary `var_literals` maps a literal
123
+ code to a pre-existing circuit variable index. Dictionary `const_literals` maps a literal
124
+ code to a constant value. A literal code should not appear in both dictionaries.
125
+
126
+ Any literal code that is parsed but does not appear in `var_literals` or `const_literals`
127
+ results in a new circuit variable being created and a corresponding entry added to
128
+ `var_literals`.
129
+
130
+ External software may modify an NNF file by removing arcs, but it may not update the header.
131
+ Although the resulting file is not conformant, it is still parsable (by ignoring the header).
132
+ Parameter `check_header` can be set to true, which causes an exception being raised if the
133
+ header disagrees with the rest of the file.
118
134
 
119
135
  Args:
120
136
  input_stream: to parse, as per `ParserInput` argument.
137
+ var_literals: an optional mapping from literal code to existing circuit variable index.
121
138
  const_literals: an optional mapping from literal code to constant value.
122
139
  circuit: an optional empty circuit to reuse.
123
140
  check_header: if true, an exception is raised if the number of nodes or arcs is not as expected.
124
141
  optimise_ops: if true then circuit optimised operations will be used.
125
142
 
126
143
  Returns:
127
- (circuit_top, literal_slot_map)
144
+ (circuit_top, var_literals)
128
145
  circuit_top: is the resulting top node from parsing the input.
129
- literal_slot_map: is a mapping from literal code (int) to a circuit var index (int).
130
-
131
- Assumes:
132
- If a circuit is provided, it is empty.
146
+ var_literals: is a mapping from literal code (int) to a circuit variable index (int).
133
147
  """
134
148
  if circuit is None:
135
149
  circuit: Circuit = Circuit()
136
150
 
137
- if circuit.number_of_vars != 0:
138
- raise ValueError('the given circuit must be empty')
151
+ if var_literals is None:
152
+ var_literals: Dict[int, int] = {}
139
153
 
140
154
  if const_literals is None:
141
155
  const_literals: Dict[int, ConstValue] = {}
142
156
 
143
- parser = CircuitParser(circuit, check_header, const_literals, optimise_ops)
157
+ parser = CircuitParser(circuit, check_header, var_literals, const_literals, optimise_ops)
144
158
  parser.parse(input_stream)
145
159
 
146
160
  nodes = parser.nodes
147
161
  cct_top = circuit.zero if len(nodes) == 0 else nodes[-1]
148
162
 
149
- return cct_top, parser.literal_slot_map
163
+ return cct_top, var_literals
150
164
 
151
165
 
152
166
  class Parser(ABC):
@@ -198,6 +212,8 @@ class Parser(ABC):
198
212
  self.add_node(raise_f, args)
199
213
  else:
200
214
  self.mul_node(raise_f, args)
215
+ else:
216
+ raise_f(f'unexpected parser state: {state}')
201
217
  line = input_stream.readline()
202
218
  self.done(raise_f)
203
219
  except ParseError as e:
@@ -236,17 +252,18 @@ class CircuitParser(Parser):
236
252
  self,
237
253
  circuit: Circuit,
238
254
  check_header: bool,
255
+ var_literals: Dict[int, int],
239
256
  const_literals: Dict[int, ConstValue],
240
257
  optimise_ops: bool,
241
258
  ):
242
259
  self.check_header: bool = check_header
243
- self.literal_slot_map: Dict[SlotKey, int] = {}
244
- self.optimise_ops = optimise_ops
245
- self.circuit = circuit
260
+ self.var_literals: Dict[int, int] = var_literals
246
261
  self.const_literals: Dict[int, ConstValue] = const_literals
262
+ self.optimise_ops: bool = optimise_ops
263
+ self.circuit: Circuit = circuit
247
264
  self.nodes: List[CircuitNode] = []
248
- self.num_nodes = None
249
- self.num_edges = None
265
+ self.num_nodes = None # read from the file header for checking
266
+ self.num_edges = None # read from the file header for checking
250
267
 
251
268
  def comment(self, raise_f, message: str) -> None:
252
269
  pass
@@ -257,13 +274,20 @@ class CircuitParser(Parser):
257
274
  """
258
275
  const_value: Optional[ConstValue] = self.const_literals.get(literal_code)
259
276
  if const_value is not None:
277
+ # Literal code maps to a constant value
278
+ if literal_code in self.var_literals:
279
+ raise_f('literal code both constant and variable: {literal_code}')
260
280
  node: ConstNode = self.circuit.const(const_value)
261
- elif literal_code in self.literal_slot_map.keys():
262
- raise_f(f'duplicated literal code: {literal_code}')
263
- return
281
+
282
+ elif (var_idx := self.var_literals.get(literal_code)) is not None:
283
+ # Literal code maps to an existing circuit variable
284
+ node: VarNode = self.circuit.vars[var_idx]
285
+
264
286
  else:
287
+ # Literal code maps to a new circuit variable
265
288
  node: VarNode = self.circuit.new_var()
266
- self.literal_slot_map[literal_code] = node.idx
289
+ self.var_literals[literal_code] = node.idx
290
+
267
291
  self.nodes.append(node)
268
292
 
269
293
  def add_node(self, raise_f, args: List[int]) -> None:
ck/in_out/parser_utils.py CHANGED
@@ -32,7 +32,7 @@ class ParserInput:
32
32
  def __init__(self, input_stream):
33
33
  self._input = _check_input(input_stream)
34
34
  self._prev_line_len = 0
35
- self._cur_line = 1
35
+ self._cur_line = 0
36
36
  self._cur_char = 1
37
37
  self._lookahead = []
38
38
 
@@ -14,6 +14,7 @@ from ck.in_out.render_net import render_bayesian_network
14
14
  from ck.pgm import PGM
15
15
  from ck.pgm_circuit import PGMCircuit
16
16
  from ck.pgm_circuit.slot_map import SlotMap
17
+ from ck.utils.local_config import config
17
18
  from ck.utils.np_extras import NDArrayFloat64
18
19
  from ck.utils.tmp_dir import tmp_dir
19
20
 
@@ -121,8 +122,9 @@ def compile_pgm(
121
122
  parameter_values: NDArrayFloat64
122
123
  circuit_top, slot_map, parameter_values = read_nnf_with_literal_map(
123
124
  file,
125
+ indicators=pgm.indicators,
124
126
  literal_map=literal_map,
125
- const_parameters=const_parameters
127
+ const_parameters=const_parameters,
126
128
  )
127
129
 
128
130
  # Consistency checking
@@ -198,8 +200,12 @@ def copy_ace_to_default_location(
198
200
  def default_ace_location() -> Path:
199
201
  """
200
202
  Get the default location for Ace files.
203
+
204
+ This function checks the local config for the variable
205
+ CK_ACE_LOCATION. If that is not available, then the
206
+ directory that this Python module is in will be used.
201
207
  """
202
- return Path(__file__).parent
208
+ return Path(config.get('CK_ACE_LOCATION', Path(__file__).parent))
203
209
 
204
210
 
205
211
  @dataclass
@@ -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
@@ -16,6 +16,7 @@ from ck_demos.utils.compare import compare
16
16
  CACHE_CIRCUITS: bool = True
17
17
  BREAK_BETWEEN_PGMS: bool = True
18
18
  COMMA_NUMBERS: bool = True
19
+ PRINT_HEADER: bool = True
19
20
 
20
21
  PGMS: Sequence[PGM] = [
21
22
  example.Rain(),
@@ -52,6 +53,7 @@ def main() -> None:
52
53
  cache_circuits=CACHE_CIRCUITS,
53
54
  break_between_pgms=BREAK_BETWEEN_PGMS,
54
55
  comma_numbers=COMMA_NUMBERS,
56
+ print_header=PRINT_HEADER,
55
57
  )
56
58
  print()
57
59
  print('Done.')
ck_demos/utils/compare.py CHANGED
@@ -16,6 +16,8 @@ def compare(
16
16
  cache_circuits: bool = True,
17
17
  break_between_pgms: bool = True,
18
18
  comma_numbers: bool = True,
19
+ print_header: bool = True,
20
+ sep: str = ' ',
19
21
  ) -> None:
20
22
  """
21
23
  For each combination of the given arguments, construct a PGMCircuit (using a
@@ -40,25 +42,34 @@ def compare(
40
42
  cache_circuits: if true, then circuits are reused across different circuit compilers.
41
43
  break_between_pgms: if true, print a blank line between different workload PGMs.
42
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.
43
47
  """
44
48
  # Work out column widths for names.
45
- col_pgm_name: int = max(len(pgm.name) for pgm in pgms)
46
- col_pgm_compiler_name: int = max(len(pgm_compiler.name) for pgm_compiler in pgm_compilers)
47
- col_cct_compiler_name: int = max(len(cct_compiler.name) for cct_compiler in cct_compilers)
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))
48
52
  col_cct_ops: int = 10
49
- col_pgm_compile_time: int = 10
50
- col_cct_compile_time: int = 10
53
+ col_pgm_compile_time: int = 16
54
+ col_cct_compile_time: int = 16
51
55
  col_execute_time: int = 10
52
56
 
57
+ # Print formatting
58
+ comma: str = ',' if comma_numbers else ''
59
+
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
+
53
69
  # Variables for when cache_circuits is true
54
70
  prev_pgm = None
55
71
  prev_pgm_compiler = None
56
72
 
57
- if comma_numbers:
58
- comma = ','
59
- else:
60
- comma = ''
61
-
62
73
  for pgm in pgms:
63
74
  pgm_name: str = pgm.name.ljust(col_pgm_name)
64
75
  for pgm_compiler in pgm_compilers:
@@ -66,23 +77,23 @@ def compare(
66
77
  for cct_compiler in cct_compilers:
67
78
  cct_compiler_name: str = cct_compiler.name.ljust(col_cct_compiler_name)
68
79
 
69
- print(f'{pgm_name} ', end='')
70
- print(f'{pgm_compiler_name} ', end='')
71
- 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)
72
83
 
73
84
  try:
74
85
  time = StopWatch()
75
86
 
76
87
  if cache_circuits and pgm is prev_pgm and pgm_compiler is prev_pgm_compiler:
77
- print(f'{"":{col_cct_ops}} ', end='')
78
- print(f'{"":{col_pgm_compile_time}} ', end='')
88
+ print(f'{"":{col_cct_ops}}', end=sep)
89
+ print(f'{"":{col_pgm_compile_time}}', end=sep)
79
90
  else:
80
91
  time.start()
81
92
  pgm_cct: PGMCircuit = pgm_compiler(pgm)
82
93
  time.stop()
83
94
  num_ops: int = pgm_cct.circuit_top.circuit.number_of_operations
84
- print(f'{num_ops:{col_cct_ops}{comma}} ', end='')
85
- print(f'{time.seconds():{col_pgm_compile_time}{comma}.3f} ', end='')
95
+ print(f'{num_ops:{col_cct_ops}{comma}}', end=sep)
96
+ print(f'{time.seconds():{col_pgm_compile_time}{comma}.3f}', end=sep)
86
97
  prev_pgm = pgm
87
98
  prev_pgm_compiler = pgm_compiler
88
99
 
@@ -91,16 +102,15 @@ def compare(
91
102
  # noinspection PyUnboundLocalVariable
92
103
  wmc = WMCProgram(pgm_cct, compiler=cct_compiler.compiler)
93
104
  time.stop()
94
- print(f'{time.seconds():{col_cct_compile_time}{comma}.3f} ', end='')
105
+ print(f'{time.seconds():{col_cct_compile_time}{comma}.3f}', end=sep)
95
106
 
96
107
  time.start()
97
108
  for _ in range(1000):
98
109
  wmc.compute()
99
110
  time.stop()
100
- print(f'{time.seconds() * 1000:{col_execute_time}{comma}.3f} ', end='')
111
+ print(f'{time.seconds() * 1000:{col_execute_time}{comma}.3f}', end=sep)
101
112
  except Exception as err:
102
113
  print(repr(err), end='')
103
-
104
114
  print()
105
115
  if break_between_pgms:
106
116
  print()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: compiled-knowledge
3
- Version: 4.0.0a15
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
@@ -2,7 +2,7 @@ ck/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  ck/pgm.py,sha256=rbqgP-clfSvgpzUXxVjk_6SdM9neHmpChku6qpyeidk,120700
3
3
  ck/circuit/__init__.py,sha256=tozFNNVzsgQDwFrtGzrgcFS4XTszhgyFmbMGfV5pimc,212
4
4
  ck/circuit/circuit.c,sha256=_DN78mWLcGdXOKoZv6Eq-m50KLpOP0SY_GjFrhLJoj0,1773051
5
- ck/circuit/circuit.cp312-win_amd64.pyd,sha256=TCkj4oiRcRFb0av5YyizlygbYKtFJn8LAqjT7nO8Zjw,252416
5
+ ck/circuit/circuit.cp312-win_amd64.pyd,sha256=T0hYyLn7cjYZ54ki85-HaKltQZcuO6oSWBtx3DNe4iI,252416
6
6
  ck/circuit/circuit.pyx,sha256=Y35CZMalySX8_uhNH6wIaZzS6ACn3rh3L99bog1lQx8,28060
7
7
  ck/circuit/circuit_node.pyx,sha256=8RuEC1ngYxnsGryzQ1lOEPc4ewTxvKwc56sOxWLB9zs,4103
8
8
  ck/circuit/circuit_py.py,sha256=_k8H1yZsfp2vERkX_CIo8VxxOf1ICw2zL8i2ckoaSlE,28127
@@ -15,7 +15,7 @@ ck/circuit_compiler/llvm_vm_compiler.py,sha256=I46_XV5FrClDKO06zIjn8T3ME5XQ9RYJ_
15
15
  ck/circuit_compiler/named_circuit_compilers.py,sha256=gKhRvYLflSCkk6CBI-CBQ2UwR-bhEhMxLvnefPm8288,2282
16
16
  ck/circuit_compiler/cython_vm_compiler/__init__.py,sha256=pEAwTleuZgdYhTAQMea2f9YsFK54eoNbZSbrWkW8aeE,49
17
17
  ck/circuit_compiler/cython_vm_compiler/_compiler.c,sha256=xpYybtj-aRcMJV1oKkB-p0kciZVW3gLRd0OJBfDg3sc,757006
18
- ck/circuit_compiler/cython_vm_compiler/_compiler.cp312-win_amd64.pyd,sha256=hq07LvGfpD8VsssyCmmbecF38YCIws2efly317jvPug,92160
18
+ ck/circuit_compiler/cython_vm_compiler/_compiler.cp312-win_amd64.pyd,sha256=XSQU7oikafjfsOaiBfI70kS2cLn69kn2CJjKgs2i5cw,92160
19
19
  ck/circuit_compiler/cython_vm_compiler/_compiler.pyx,sha256=hHuNo99TbodNpWgQwQ8qzW1cTwGXZj5SW0tKAo9u6cw,7718
20
20
  ck/circuit_compiler/cython_vm_compiler/cython_vm_compiler.py,sha256=yUkBNr5HnoVXyWjJdXHp8lyAXFiIDYapvMvHtzKuhI8,3140
21
21
  ck/circuit_compiler/support/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -55,9 +55,9 @@ ck/example/triangle_square.py,sha256=D-ADGOSxCffsgukLTySsb6HVQpUnOJ-ZyMGBz_qGna4
55
55
  ck/example/truss.py,sha256=5ud1qvPZMSKqSx0Sq1ZKcEeD_ZVUdKbEBfk5eyqhpm4,1974
56
56
  ck/in_out/__init__.py,sha256=PKhy5qeUrmmUaECSQIkoLQ2McAfQFSwB06vQZk3vpmo,112
57
57
  ck/in_out/parse_ace_lmap.py,sha256=EZnSLhsZwdPnk2Fbe2El0YXYqvjd_cBh7PZro7ZeR04,7891
58
- ck/in_out/parse_ace_nnf.py,sha256=Hkc24qn4ziA4-VunBEinURDGsnmCWICj73w3bopecR0,11843
58
+ ck/in_out/parse_ace_nnf.py,sha256=zO3smkKKiUy_g0S7WeNyhEaZu5x65wuSNIDWlA3YU_g,13350
59
59
  ck/in_out/parse_net.py,sha256=cBY7X4k5U8v9x_dtFZWdOpSPh-q-U47gdImNo2Tf9dY,14302
60
- ck/in_out/parser_utils.py,sha256=Js_BaOmNji4mM7UYDm6pGd56wYcQoere7TuB0tkztko,5440
60
+ ck/in_out/parser_utils.py,sha256=IKwgXBrIhHdL85n92RzB5yau_ja7DB3iAV-FHMgWsnI,5440
61
61
  ck/in_out/pgm_pickle.py,sha256=i5LYxez356we7MzHwsQBmFdOvBJOLVKBp4u4lSwBOjU,1004
62
62
  ck/in_out/pgm_python.py,sha256=c2-yxXxJ4fF00gUD5Lvt_CSE07EgwYeHW3nSNXunEvc,10092
63
63
  ck/in_out/render_bugs.py,sha256=6YBhMIq3VRKFS0XqHbaWj6iz1io7O9icW23kukF_Cic,3383
@@ -80,7 +80,7 @@ ck/pgm_compiler/pgm_compiler.py,sha256=F44PtlwqMG0FS6KzOYKZuyZT6olWAVtBH-QXZPzz4
80
80
  ck/pgm_compiler/recursive_conditioning.py,sha256=U0NdIns8yLQtYR_MOf1w__CChpOMDlgRCL2nFRhtnzU,7936
81
81
  ck/pgm_compiler/variable_elimination.py,sha256=YNBurWTz8_BoaZgRZFj-T9gRVGek7ZutGkvjegyLkCM,3460
82
82
  ck/pgm_compiler/ace/__init__.py,sha256=BkZXAF32Pk8QU7jhkuKvHqtsFasPjf8gxiZbyrGDDbQ,82
83
- ck/pgm_compiler/ace/ace.py,sha256=Q3d76rwAMsNFQeRXdxycy_KUJeE29g7bURryKAdq-aI,10095
83
+ ck/pgm_compiler/ace/ace.py,sha256=iyDacqArXW1cVP6tBabxRmmLWIHabuPkCoq2tWBm2ww,10397
84
84
  ck/pgm_compiler/support/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
85
  ck/pgm_compiler/support/clusters.py,sha256=96Up5XUgERh-t6KzSIOF2gtP5T4Ul83JK_aPtIR72Ic,20821
86
86
  ck/pgm_compiler/support/factor_tables.py,sha256=N7BNBBA-BX6RN-eiDwENtMLczW3JAkV-qW0i0k8OZEM,15558
@@ -88,7 +88,7 @@ ck/pgm_compiler/support/join_tree.py,sha256=tRHev655cwRsOSyLK9HYwfX8EEkubmlg1fw7
88
88
  ck/pgm_compiler/support/named_compiler_maker.py,sha256=tQ79JOI8MknAziUiFhFGV9n4y6PPKrnbq3-quMmnrwY,974
89
89
  ck/pgm_compiler/support/circuit_table/__init__.py,sha256=eWMP5ywgd51RJexKkhcpKJb_8iEluL0C4_hyOpzlAvQ,167
90
90
  ck/pgm_compiler/support/circuit_table/circuit_table.c,sha256=aO3bq3V-FwbmJDzWVYwigOFeQUC6gFz-nAq091XQp2E,702527
91
- ck/pgm_compiler/support/circuit_table/circuit_table.cp312-win_amd64.pyd,sha256=eVXmnKKG8k-V0v_RfhH9_n8nHfB6zZtC5LPDAvHitY0,94720
91
+ ck/pgm_compiler/support/circuit_table/circuit_table.cp312-win_amd64.pyd,sha256=D8n3mBrIXbSPyFVOWJUwKb7F3h1O1SXmdGq7igfQFpA,94720
92
92
  ck/pgm_compiler/support/circuit_table/circuit_table.pyx,sha256=jhzstay-3EUgu0CIbWKd0eNDNToX1tmm9IQxk0ZgpYM,11904
93
93
  ck/pgm_compiler/support/circuit_table/circuit_table_py.py,sha256=1WFCxgBFu4oaYRCdk_1uXeufFQu6PqMOsYIQ_SkXDS4,10156
94
94
  ck/probability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -111,6 +111,7 @@ ck/sampling/wmc_metropolis_sampler.py,sha256=PRv7wtPZz7BcwN8iArsykVwqgY77v5km7rX
111
111
  ck/sampling/wmc_rejection_sampler.py,sha256=cd0VONZf-oa491RRKfwT2LakQs0o_slgPCes8AOvSNc,4897
112
112
  ck/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
113
113
  ck/utils/iter_extras.py,sha256=DDml5Jprmun2RovJxkwXx1uJkWacYhZEnX1ARSX2TB4,4310
114
+ ck/utils/local_config.py,sha256=-oTKvKCpm29JeHEhV1_qLC5fMS523unDzXr0VYE3M0U,9535
114
115
  ck/utils/map_list.py,sha256=T2OpjI7eDgC4geCtW_FsEr6ryiePOnKZwfDahB63zfA,3847
115
116
  ck/utils/map_set.py,sha256=BLu9BO3FCtzZlZ9MfP9STtIdQ4Me8-QKdwB7o15y7f8,3809
116
117
  ck/utils/np_extras.py,sha256=J5KIQJX3C79ltAfKKYc0B0HI43iyuUQxLI9HZ9FiORI,1734
@@ -133,7 +134,7 @@ ck_demos/pgm/demo_pgm_dump_stress.py,sha256=L9S3yp0EQM56kWztV4A6XzEqITOGbThImZIU
133
134
  ck_demos/pgm/demo_pgm_string_rendering.py,sha256=JTf_M6pPwl9RtOLlpJFQIgNgGuHnsddJbxhgbZOChos,285
134
135
  ck_demos/pgm/show_examples.py,sha256=KxK37hKqWD9w9k9RoMCdJgkBIMePf8udQbqaFs-s91c,461
135
136
  ck_demos/pgm_compiler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
- ck_demos/pgm_compiler/compare_pgm_compilers.py,sha256=0dm77DygI9E4WMOAD-M8Kzrf4xlPmZuZX6zUdy5fZ4Y,1548
137
+ ck_demos/pgm_compiler/compare_pgm_compilers.py,sha256=pG0OQBl2wjdCIUU0RM70j8TfCjYUxRU0i13OWpfXUHc,1611
137
138
  ck_demos/pgm_compiler/demo_compiler_dump.py,sha256=OlLJi1wwdFQxave5lpceyVx0-ihHEn2-d-0XFFTjowY,1370
138
139
  ck_demos/pgm_compiler/demo_factor_elimination.py,sha256=KDzYwNZJ9HTcPoNxg6lxFoaXJ26QW-nnBI-0Ux_yWoM,1320
139
140
  ck_demos/pgm_compiler/demo_join_tree.py,sha256=E7ZqFrRuAmnSRmBTDqNGxD-KFlHOtd_jIju8UJssUfM,574
@@ -161,12 +162,12 @@ ck_demos/sampling/demo_marginal_direct_sampler.py,sha256=RhNunuIUnYI_GXp9m8wzadM
161
162
  ck_demos/sampling/demo_uniform_sampler.py,sha256=Z6tX_OYKGLc_w3-kEPK4KEZlJo7F5HOq_tUVppB_VQE,962
162
163
  ck_demos/sampling/demo_wmc_direct_sampler.py,sha256=c7maxTmZyIijaVdFs2h_KQbK30LvI-oCm2BXSUXVoD8,1113
163
164
  ck_demos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
- ck_demos/utils/compare.py,sha256=WGCYv6rbT_vU1ldndnIoflmF2EDAQ2ckCw2i2QVVPng,4357
165
+ ck_demos/utils/compare.py,sha256=MwigxgMqeV7slrzdIJYVJ340QBCCXOeUzUKOJkkd98w,4972
165
166
  ck_demos/utils/convert_network.py,sha256=TSKj8q7L7J5rhrvwjaDkdYZ0Sg8vV5FRL_vCanX1CQw,1363
166
167
  ck_demos/utils/sample_model.py,sha256=in-Nlv-iuNIu6y9fDuMyo7nzgimBuTAnCWcpnVqvqDQ,8839
167
168
  ck_demos/utils/stop_watch.py,sha256=VzXHRWx0V8vPSD-bLgLlEYkCkR2FA0-KmM_pfKx-Pxo,13205
168
- compiled_knowledge-4.0.0a15.dist-info/licenses/LICENSE.txt,sha256=uMYx7tmroEKNASizbCOwPveMQsD5UErLDC1_SANmNn8,1089
169
- compiled_knowledge-4.0.0a15.dist-info/METADATA,sha256=2pLUAaU9vrC3iWkLGsj6SPKfKQDSZ8UL2eBh9xdkF4k,1838
170
- compiled_knowledge-4.0.0a15.dist-info/WHEEL,sha256=b7PoVIxzH_MOHKjftqMzQiGKfdHRlRFepVBVPg0y3vc,101
171
- compiled_knowledge-4.0.0a15.dist-info/top_level.txt,sha256=Cf8DAfd2vcnLiA7HlxoduOzV0Q-8surE3kzX8P9qdks,12
172
- compiled_knowledge-4.0.0a15.dist-info/RECORD,,
169
+ compiled_knowledge-4.0.0a16.dist-info/licenses/LICENSE.txt,sha256=uMYx7tmroEKNASizbCOwPveMQsD5UErLDC1_SANmNn8,1089
170
+ compiled_knowledge-4.0.0a16.dist-info/METADATA,sha256=5y-1ZXcu9vGc2PE6lccfgtWTwjOstq_vY0Uk6OT9AQc,1838
171
+ compiled_knowledge-4.0.0a16.dist-info/WHEEL,sha256=b7PoVIxzH_MOHKjftqMzQiGKfdHRlRFepVBVPg0y3vc,101
172
+ compiled_knowledge-4.0.0a16.dist-info/top_level.txt,sha256=Cf8DAfd2vcnLiA7HlxoduOzV0Q-8surE3kzX8P9qdks,12
173
+ compiled_knowledge-4.0.0a16.dist-info/RECORD,,