Skip to content

Commit 8b78cf7

Browse files
Node attribute storage in nodes (runtimeverification/pyk#1002)
Fixes: runtimeverification/pyk#965 Stores node attributes `terminal`,`stuck`, and `vacuous` in nodes rather than in KCFG or KCFGExploration. - adds `attr` field to KCFG.Node - adds enums `NodeAttr` (base), `KCFGNodeAttr`, and `KCFGExplorationNodeAttr` - adds `add_attr`, `remove_attr`, and `discard_attr` to kcfg for updating the attrs of a given node, which replaces the node with a new one, since nodes are immutable. - `replace_node` now takes a node. `let_node` is now for updating specific fields of nodes. - Checks `terminal`, `stuck`, and `vacuous` by reference to the attributes on the node - Removes separate `terminal`, `stuck` and `vacuous` lists. - `from_dict` and `to_dict` on `Node` and `KCFG` updated to store relevant attributes in the node dicts. `KCFGStore` translates to and from the existing on-disk format. - Tests in `test_proof.py` previously using `read_proof` and `write_proof` are now using `read_proof_data` and `write_proof_data`, since the older way of reading and writing does not use the `KCFGStore` and relies on `KCFG.to_dict` directly, without the translation. --------- Co-authored-by: devops <[email protected]>
1 parent 5224d56 commit 8b78cf7

File tree

13 files changed

+221
-115
lines changed

13 files changed

+221
-115
lines changed

pyk/docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
project = 'pyk'
1010
author = 'Runtime Verification, Inc'
1111
copyright = '2024, Runtime Verification, Inc'
12-
version = '0.1.756'
13-
release = '0.1.756'
12+
version = '0.1.757'
13+
release = '0.1.757'
1414

1515
# -- General configuration ---------------------------------------------------
1616
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

pyk/package/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.756
1+
0.1.757

pyk/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "pyk"
7-
version = "0.1.756"
7+
version = "0.1.757"
88
description = ""
99
authors = [
1010
"Runtime Verification, Inc. <[email protected]>",

pyk/src/pyk/kcfg/exploration.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from typing import TYPE_CHECKING
44

5-
from pyk.kcfg.kcfg import KCFG
5+
from pyk.kcfg.kcfg import KCFG, NodeAttr
66

77
if TYPE_CHECKING:
88
from collections.abc import Iterable, Mapping
@@ -11,21 +11,30 @@
1111
from pyk.kcfg.kcfg import NodeIdLike
1212

1313

14+
class KCFGExplorationNodeAttr(NodeAttr):
15+
TERMINAL = NodeAttr('terminal')
16+
17+
1418
class KCFGExploration:
1519
kcfg: KCFG
16-
_terminal: set[int]
1720

1821
def __init__(self, kcfg: KCFG, terminal: Iterable[NodeIdLike] | None = None) -> None:
1922
self.kcfg = kcfg
20-
self._terminal = {kcfg._resolve(node_id) for node_id in terminal} if terminal is not None else set()
23+
if terminal:
24+
for node_id in terminal:
25+
self.add_terminal(node_id)
26+
27+
@property
28+
def terminal_ids(self) -> set[int]:
29+
return {node.id for node in self.kcfg.nodes if KCFGExplorationNodeAttr.TERMINAL in node.attrs}
2130

2231
#
2332
# Recognisers
2433
#
2534

2635
# Terminal node recogniser
2736
def is_terminal(self, node_id: NodeIdLike) -> bool:
28-
return self.kcfg._resolve(node_id) in self._terminal
37+
return KCFGExplorationNodeAttr.TERMINAL in self.kcfg.node(node_id).attrs
2938

3039
# Explorable node recogniser
3140
def is_explorable(self, node_id: NodeIdLike) -> bool:
@@ -56,11 +65,11 @@ def explorable(self) -> list[KCFG.Node]:
5665

5766
# Marking a given node as terminal
5867
def add_terminal(self, node_id: NodeIdLike) -> None:
59-
self._terminal.add(self.kcfg._resolve(node_id))
68+
self.kcfg.add_attr(node_id, KCFGExplorationNodeAttr.TERMINAL)
6069

6170
# Unmarking a given node as terminal
6271
def remove_terminal(self, node_id: int) -> None:
63-
self._terminal.discard(node_id)
72+
self.kcfg.remove_attr(node_id, KCFGExplorationNodeAttr.TERMINAL)
6473

6574
#
6675
# Lifted KCFG functions that may affect terminal nodes
@@ -70,14 +79,10 @@ def remove_terminal(self, node_id: int) -> None:
7079
def remove_node(self, node_id: NodeIdLike) -> None:
7180
node_id = self.kcfg._resolve(node_id)
7281
self.kcfg.remove_node(node_id)
73-
self.remove_terminal(node_id)
7482

7583
# Pruning a KCFG subtree starting from a given node
7684
def prune(self, node_id: NodeIdLike, keep_nodes: Iterable[NodeIdLike] = ()) -> list[int]:
77-
pruned_nodes = self.kcfg.prune(node_id, keep_nodes=keep_nodes)
78-
for node_id in pruned_nodes:
79-
self.remove_terminal(node_id)
80-
return pruned_nodes
85+
return self.kcfg.prune(node_id, keep_nodes=keep_nodes)
8186

8287
#
8388
# Dictionarisation
@@ -95,7 +100,7 @@ def from_dict(dct: Mapping[str, Any]) -> KCFGExploration:
95100
def to_dict(self) -> dict[str, Any]:
96101
dct: dict[str, Any] = {}
97102
dct['kcfg'] = self.kcfg.to_dict()
98-
dct['terminal'] = sorted(self._terminal)
103+
dct['terminal'] = sorted(node.id for node in self.kcfg.nodes if self.is_terminal(node.id))
99104
return dct
100105

101106
#
@@ -105,4 +110,3 @@ def to_dict(self) -> dict[str, Any]:
105110
# Minimizing the KCFG
106111
def minimize_kcfg(self) -> None:
107112
self.kcfg.minimize()
108-
self._terminal = self._terminal.difference(self.kcfg._deleted_nodes)

pyk/src/pyk/kcfg/explore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def simplify(self, cfg: KCFG, logs: dict[int, tuple[LogEntry, ...]]) -> None:
116116
_LOGGER.info(f'Simplifying node {self.id}: {shorten_hashes(node.id)}')
117117
new_term, next_node_logs = self.cterm_symbolic.simplify(node.cterm)
118118
if new_term != node.cterm:
119-
cfg.replace_node(node.id, new_term)
119+
cfg.let_node(node.id, cterm=new_term)
120120
if node.id in logs:
121121
logs[node.id] += next_node_logs
122122
else:

0 commit comments

Comments
 (0)