From d6496ec77f1f74f7489bb69a976b9339bcd15a70 Mon Sep 17 00:00:00 2001 From: T-Flet Date: Sat, 26 Aug 2023 16:09:30 +0100 Subject: [PATCH] Version bump to 3.2 (mostly for last commit). Improved optional warning suppression for graph topology features and lossy shorthand reversal. Added a greedy_updater field to GSMs and a greedy flag for steps to add all candidates to state. --- .github/workflows/pythonpackage.yml | 2 +- GSM_Diagram.png | Bin 0 -> 60551 bytes Graph_State_Machine/Util/misc.py | 6 +++--- Graph_State_Machine/__init__.py | 2 +- Graph_State_Machine/graph.py | 4 ++-- Graph_State_Machine/gsm.py | 25 ++++++++++++++----------- Graph_State_Machine/updaters.py | 8 ++++++++ README.rst | 16 ++++++++++++---- setup.py | 6 +++++- 9 files changed, 46 insertions(+), 23 deletions(-) create mode 100644 GSM_Diagram.png diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 9d27ef6..27f5125 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -10,7 +10,7 @@ jobs: max-parallel: 4 matrix: os: [windows-latest, ubuntu-latest, macOS-latest] - python-version: [3.8] + python-version: ["3.10"] steps: - uses: actions/checkout@v1 diff --git a/GSM_Diagram.png b/GSM_Diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..3072d7eaa61554e1462e108c1153bc53580dfbe4 GIT binary patch literal 60551 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
~64nZd#dhvUBOQ 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 KcB^xtvHt|GyU2n7 literal 0 HcmV?d00001 diff --git a/Graph_State_Machine/Util/misc.py b/Graph_State_Machine/Util/misc.py index 4e6b6a9..76bd0f7 100644 --- a/Graph_State_Machine/Util/misc.py +++ b/Graph_State_Machine/Util/misc.py @@ -11,7 +11,7 @@ def check_edge_dict_keys(dict_many: Dict[str, List[str]]) -> None: assert not (bad_keys := [k for k in dict_many.keys() if k not in ok_keys]), f'The only keys allowed in graph-shortand edge dictionaries are {ok_keys}; the following bad keys were provided: {bad_keys}' -def reverse_adjacencies(one_type_graph: Dict[str, List[str]], allow_losing_singletons = False, allow_losing_joint_sufficiency = False) -> Dict[str, List[str]]: +def reverse_adjacencies(one_type_graph: Dict[str, List[str]], allow_losing_singletons = False, allow_losing_joint_sufficiency = False, suppress_warnings = False) -> Dict[str, List[str]]: '''Invert a dictionary of adjacencies, possibly losing singletons, e.g. {A: [B, C], D: []} -> {B: [A], C: [A]}''' if not allow_losing_singletons: assert not (singletons := [k for k, v in one_type_graph.items() if not v]), f'Singletons {singletons} loss prevented in reverse_adjacencies; set allow_losing_singletons to True to allow it (but check carefully first)' opposite = dict(are_necessary = 'necessary_for', are_sufficient = 'sufficient_for', necessary_for = 'are_necessary', sufficient_for = 'are_sufficient', plain = 'plain') @@ -29,8 +29,8 @@ def reverse_adjacencies(one_type_graph: Dict[str, List[str]], allow_losing_singl for edge_type, end in [(t, e) for t, es in ends.items() for e in es]: if isinstance(end, list): if allow_losing_joint_sufficiency: - warn(f"Allowing lossy reversal of Node sub-list {end} in adjacency key '{edge_type}'; i.e. these edges will be plain when reversed; " - f"if these are intended joint sufficiencies, ensure they are declared on the '{start}' side; set allow_losing_joint_sufficiency to False to prevent this") + if not suppress_warnings: warn(f"Allowing lossy reversal of Node sub-list {end} in adjacency key '{edge_type}'; i.e. these edges will be plain when reversed; " + f"if these are intended joint sufficiencies, ensure they are declared on the '{start}' side; set allow_losing_joint_sufficiency to False to prevent this") pairs += [('plain', e) for e in end] else: raise ValueError(f"Within reverse_adjacencies, all the values within adjacency dictionaries need to be simple lists of Nodes (normally 'are_sufficient' is allowed sub-lists for joint sufficiency); " f"instead, '{start}''s '{edge_type}' contained the list {end}; " diff --git a/Graph_State_Machine/__init__.py b/Graph_State_Machine/__init__.py index ca92988..17c9b75 100644 --- a/Graph_State_Machine/__init__.py +++ b/Graph_State_Machine/__init__.py @@ -1,6 +1,6 @@ """Graph-State-Machine - A simple library to build easily interpretable computational constructs similar to a Turing machine over a graph, where states are combinations of a graph's (typed) nodes; an example use would be a transparent backend logic which navigates an ontology""" -__version__ = '3.1' # Change it in setup.py too +__version__ = '3.2' # Change it in setup.py too __author__ = 'Thomas Fletcher ' # __all__ = ['Graph', 'GSM'] diff --git a/Graph_State_Machine/graph.py b/Graph_State_Machine/graph.py index ec9dfd3..895951a 100644 --- a/Graph_State_Machine/graph.py +++ b/Graph_State_Machine/graph.py @@ -135,10 +135,10 @@ def group_nodes(self, nodes: List[Node] = None) -> Dict[NodeType, List[Node]]: unsorted = group_by(lambda n: self.nodes_to_types[n], nodes if nodes else self.G.nodes()) return {nt: unsorted[nt] for nt in sorted(unsorted)} - def extend_with(self, extension_graph): + def extend_with(self, extension_graph, warn_about_problematic_sufficiencies = True): '''Note: returns a new object; does not affect the original''' res = deepcopy(self) - return res._set_graph(nx.compose(res.G, extension_graph.G)) + return res._set_graph(nx.compose(res.G, extension_graph.G), warn_about_problematic_sufficiencies) # Utility methods diff --git a/Graph_State_Machine/gsm.py b/Graph_State_Machine/gsm.py index 886e91f..997f334 100644 --- a/Graph_State_Machine/gsm.py +++ b/Graph_State_Machine/gsm.py @@ -6,14 +6,15 @@ from Graph_State_Machine.selectors import identity from Graph_State_Machine.scanners import by_score -from Graph_State_Machine.updaters import list_accumulator +from Graph_State_Machine.updaters import list_accumulator, list_accumulator_greedy from Graph_State_Machine.types import * from Graph_State_Machine.Util.misc import expand_user_warning class GSM: def __init__(self, graph: Graph, state: State = [], - node_scanner: Scanner = by_score(), state_updater: Updater = list_accumulator, selector = identity): + node_scanner: Scanner = by_score(), state_updater: Updater = list_accumulator, selector = identity, + greedy_state_updater: Updater = list_accumulator_greedy): '''Define a Graph State Machine by providing the starting graph and state and the two operation functions: - the scanner, which assigns scores to nodes of interest given the state nodes (e.g. their neighbours) - the updater, which updates the state based on the scanner's output; it can update the graph too (though it does not have to) @@ -26,6 +27,7 @@ def __init__(self, graph: Graph, state: State = [], self.state = state self.selector = selector self.updater = state_updater + self.greedy_updater = greedy_state_updater self.log = [dict(method = '__init__', graph = graph, state = state, node_scanner = node_scanner, state_updater = state_updater, list_accumulator = list_accumulator, selector = selector)] @@ -35,21 +37,22 @@ def __str__(self): return f'GSM State: {self.state.__str__()}' # Core functionality methods - def extend_with(self, extension_graph): + def extend_with(self, extension_graph, warn_about_problematic_sufficiencies = True): '''Note: returns a new object; does not affect the original''' res = deepcopy(self) - res.graph = res.graph.extend_with(extension_graph) + res.graph = res.graph.extend_with(extension_graph, warn_about_problematic_sufficiencies) return res def _scan(self, *args, **kwargs) -> List[Tuple[Node, Any]]: '''Note: this method just returns the step result; it does not update the state''' return self.scanner(self.graph, self.selector(self.state), *args, **kwargs) - def step(self, *args, conditional = False, **kwargs): + def step(self, *args, conditional = False, greedy = False, **kwargs): '''Scan nodes of interest and perform a step (i.e. have the step_handler update the state by processing the scan result). If conditional == True, the step is performed only if no node of the requested type is in state. In that case an ASSUMPTION is made: - that the first (named or unnamed) argument of scanner (after graph and state) is a singleton list of the type of node to look for''' + that the first (named or unnamed) argument of scanner (after graph and state) is a singleton list of the type of node to look for. + If greedy == True, then the step uses the self.greedy_updater updater (THE DEFAULT ONE IS ONLY FOR LIST-TYPE STATES), adding ALL candidates to state.''' if args and kwargs: raise TypeError('Step function arguments should be either all named or all unnamed (except for "conditional", which should always be named)') node_type = (args if args else (list(kwargs.values())))[0][0] if conditional and self.type_in_state(node_type): @@ -59,17 +62,17 @@ def step(self, *args, conditional = False, **kwargs): def f(): scan_result = self._scan(*args, **kwargs) self.log.append(dict(method = 'step', scan_result = scan_result, scanner_arguments = self._ensure_scanner_args_are_named(args, kwargs))) - self.state, self.graph = self.updater(self.state, self.graph, scan_result) + self.state, self.graph = (self.greedy_updater if greedy else self.updater)(self.state, self.graph, scan_result) expand_user_warning(f, lambda: f'; last log entry: {self.log[-1]}') return self - def consecutive_steps(self, *scanners_arguments: List[Union[List, Dict]], conditional = False): + def consecutive_steps(self, *scanners_arguments: List[Union[List, Dict]], conditional = False, greedy = False): '''Perform steps of the given node types one after the other, i.e. using the progressively updated state for each new step. Note: steps can be made either all standard or all conditional.''' - for ss in scanners_arguments: self.step(**self._ensure_scanner_args_are_named(ss), conditional = conditional) + for ss in scanners_arguments: self.step(**self._ensure_scanner_args_are_named(ss), conditional = conditional, greedy = greedy) return self - def parallel_steps(self, *scanners_arguments: List[Union[List, Dict]], conditional = False): + def parallel_steps(self, *scanners_arguments: List[Union[List, Dict]], conditional = False, greedy = False): '''Perform steps of the given node types all starting from the same state, i.e. only apply state updates after scan results are known. Note: steps can be made either all standard or all conditional.''' scanners_arguments = [self._ensure_scanner_args_are_named(ss) for ss in scanners_arguments] @@ -80,7 +83,7 @@ def parallel_steps(self, *scanners_arguments: List[Union[List, Dict]], condition warnings.warn(f'Step of type \'{node_type}\' not taken because nodes of that type were already in state') return self else: - def f(): self.state, self.graph = self.updater(self.state, self.graph, rs) + def f(): self.state, self.graph = (self.greedy_updater if greedy else self.updater)(self.state, self.graph, rs) expand_user_warning(f, lambda: f'; (parallel) step arguments: {ss}') self.log.append(dict(method = 'parallel_steps', scan_results = scan_results, scanners_arguments = scanners_arguments)) return self diff --git a/Graph_State_Machine/updaters.py b/Graph_State_Machine/updaters.py index 66eb635..f6b151a 100644 --- a/Graph_State_Machine/updaters.py +++ b/Graph_State_Machine/updaters.py @@ -25,3 +25,11 @@ def dict_accumulator_closure(state: State, graph: Graph, scan_result: ScanResult return dict_accumulator_closure +def list_accumulator_greedy(state: State, graph: Graph, scan_result: ScanResult) -> Tuple[State, Graph]: + '''Never removes from state and adds ALL NODES from step_result to a simple-list state''' + if scan_result: return state + scan_result[0], graph + else: + warn('A Scanner returned no result: no appropriate candidates identified') + return state, graph + + diff --git a/README.rst b/README.rst index 6232122..5a36df4 100644 --- a/README.rst +++ b/README.rst @@ -54,6 +54,14 @@ Given a graph with typed nodes and a state object from which a list of nodes can :code:`Updater` A function to process the scan result and thus update the state and possibly the graph itself + +.. figure:: GSM_Diagram.png + :align: center + :figclass: align-center + + Schematic representation of a GSM step (with data flow in dashed arrows) + + This computational construct is different from a finite state machine on a graph and from a graph cellular automaton, but it shares some similarities with both in that it generalises some of their features for the benefit of human ease of design and readability. @@ -219,10 +227,10 @@ A small GSM which selects the appropriate R linear regression function and distr 'Distribution': { 'Normal': ['stan_glm', 'glm', 'gaussian'], 'Binomial': ['stan_glm', 'glm', 'binomial'], - 'Multinomial': ['stan_polr', 'polr_tolerant', 'multinom'], + 'Categorical': ['stan_polr', 'polr_tolerant', 'multinom'], 'Poisson': ['stan_glm', 'glm', 'poisson'], 'Beta': ['stan_betareg', 'betareg'], - 'gamma': ['stan_glm', 'glm', 'Gamma'], + 'Gamma_': ['stan_glm', 'glm', 'Gamma'], 'Inverse Gaussian': ['stan_glm', 'glm', 'inverse.gaussian'] }, 'Family Implementation': strs_as_keys(['binomial', 'poisson', 'Gamma', 'gaussian', 'inverse.gaussian']), @@ -230,10 +238,10 @@ A small GSM which selects the appropriate R linear regression function and distr 'Data Feature': reverse_adjacencies({ # Reverse-direction definition here since more readable i.e. defining the contents of the lists 'Binomial': ['Binary', 'Integer', '[0,1]', 'Boolean'], 'Poisson': ['Non-Negative', 'Integer', 'Consecutive', 'Counts-Like'], - 'Multinomial': ['Factor', 'Consecutive', 'Non-Negative', 'Integer'], + 'Categorical': ['Factor', 'Consecutive', 'Non-Negative', 'Integer'], 'Normal': ['Integer', 'Real', '+ and -'], 'Beta': ['Real', '[0,1]'], - 'gamma': ['Non-Negative', 'Integer', 'Real', 'Non-Zero'], + 'Gamma_': ['Non-Negative', 'Integer', 'Real', 'Non-Zero'], 'Inverse Gaussian': ['Non-Negative', 'Integer', 'Real', 'Non-Zero'], 'polr_tolerant': ['Consecutive'] }) diff --git a/setup.py b/setup.py index 5ea3978..c46ebfb 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ def read_requirements(): setup( name = 'Graph-State-Machine', - version = '3.1', # Update in package __init__ too + version = '3.2', # Update in package __init__ too url = 'https://github.com/T-Flet/Graph-State-Machine', license = 'BSD 3-Clause', @@ -37,5 +37,9 @@ def read_requirements(): 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12' ] )