Skip to content

Commit a108dc1

Browse files
ovatmanrv-auditor
authored andcommitted
cache prior loops discovered in bmc (runtimeverification/pyk#922)
This pr adds a `prior_loops_cache` that holds a dictionary of {loop : prior same loops} that has been discovered so far. During `bmc_depth` bound checking the new loop node's cache is populated with the previously discovered same nodes. The cache is also written/read as proof data. Closes: runtimeverification/kontrol#283 --------- Co-authored-by: devops <[email protected]> Co-authored-by: Tolga Ovatman <[email protected]>
1 parent dac43c5 commit a108dc1

File tree

4 files changed

+33
-16
lines changed

4 files changed

+33
-16
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.694'
13-
release = '0.1.694'
12+
version = '0.1.695'
13+
release = '0.1.695'
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.694
1+
0.1.695

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.694"
7+
version = "0.1.695"
88
description = ""
99
authors = [
1010
"Runtime Verification, Inc. <[email protected]>",

pyk/src/pyk/proof/reachability.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class APRProof(Proof, KCFGExploration):
8080
circularity: bool
8181
_exec_time: float
8282
error_info: Exception | None
83+
prior_loops_cache: dict[int, list[int]]
8384

8485
def __init__(
8586
self,
@@ -98,6 +99,7 @@ def __init__(
9899
admitted: bool = False,
99100
_exec_time: float = 0,
100101
error_info: Exception | None = None,
102+
prior_loops_cache: dict[int, list[int]] | None = None,
101103
):
102104
Proof.__init__(self, id, proof_dir=proof_dir, subproof_ids=subproof_ids, admitted=admitted)
103105
KCFGExploration.__init__(self, kcfg, terminal)
@@ -110,6 +112,7 @@ def __init__(
110112
self.logs = logs
111113
self.circularity = circularity
112114
self.node_refutations = {}
115+
self.prior_loops_cache = prior_loops_cache if prior_loops_cache is not None else {}
113116
self.kcfg._kcfg_store = KCFGStore(self.proof_subdir / 'kcfg') if self.proof_subdir else None
114117
self._exec_time = _exec_time
115118
self.error_info = error_info
@@ -201,6 +204,12 @@ def prune(self, node_id: NodeIdLike, keep_nodes: Iterable[NodeIdLike] = ()) -> l
201204
pruned_nodes = super().prune(node_id, keep_nodes=list(keep_nodes) + [self.init, self.target])
202205
for nid in pruned_nodes:
203206
self._bounded.discard(nid)
207+
for k, v in self.prior_loops_cache.items():
208+
if k == nid:
209+
self.prior_loops_cache.pop(k)
210+
elif nid in v:
211+
self.prior_loops_cache[k].remove(nid)
212+
204213
return pruned_nodes
205214

206215
@property
@@ -481,6 +490,8 @@ def read_proof_data(proof_dir: Path, id: str) -> APRProof:
481490
kcfg._resolve(int(node_id)): proof_id for node_id, proof_id in proof_dict['node_refutations'].items()
482491
}
483492

493+
prior_loops_cache = {int(k): v for k, v in proof_dict.get('loops_cache', {}).items()}
494+
484495
return APRProof(
485496
id=id,
486497
kcfg=kcfg,
@@ -495,6 +506,7 @@ def read_proof_data(proof_dir: Path, id: str) -> APRProof:
495506
proof_dir=proof_dir,
496507
subproof_ids=subproof_ids,
497508
node_refutations=node_refutations,
509+
prior_loops_cache=prior_loops_cache,
498510
_exec_time=exec_time,
499511
)
500512

@@ -526,6 +538,8 @@ def write_proof_data(self) -> None:
526538
if self.bmc_depth is not None:
527539
dct['bmc_depth'] = self.bmc_depth
528540

541+
dct['loops_cache'] = self.prior_loops_cache
542+
529543
proof_json.write_text(json.dumps(dct))
530544
_LOGGER.info(f'Wrote proof data for {self.id}: {proof_json}')
531545
self.kcfg.write_cfg_data()
@@ -717,18 +731,21 @@ def step_proof(self) -> Iterable[StepResult]:
717731
if self.proof.bmc_depth is not None and curr_node.id not in self._checked_for_bounded:
718732
_LOGGER.info(f'Checking bmc depth for node {self.proof.id}: {curr_node.id}')
719733
self._checked_for_bounded.add(curr_node.id)
720-
_prior_loops = [
721-
succ.source.id
722-
for succ in self.proof.shortest_path_to(curr_node.id)
723-
if self.kcfg_explore.kcfg_semantics.same_loop(succ.source.cterm, curr_node.cterm)
724-
]
725-
prior_loops: list[NodeIdLike] = []
726-
for _pl in _prior_loops:
727-
if not (
728-
self.proof.kcfg.zero_depth_between(_pl, curr_node.id)
729-
or any(self.proof.kcfg.zero_depth_between(_pl, pl) for pl in prior_loops)
730-
):
731-
prior_loops.append(_pl)
734+
735+
prior_loops = []
736+
for succ in reversed(self.proof.shortest_path_to(curr_node.id)):
737+
if self.kcfg_explore.kcfg_semantics.same_loop(succ.source.cterm, curr_node.cterm):
738+
if succ.source.id in self.proof.prior_loops_cache:
739+
if self.proof.kcfg.zero_depth_between(succ.source.id, curr_node.id):
740+
prior_loops = self.proof.prior_loops_cache[succ.source.id]
741+
else:
742+
prior_loops = self.proof.prior_loops_cache[succ.source.id] + [succ.source.id]
743+
break
744+
else:
745+
self.proof.prior_loops_cache[succ.source.id] = []
746+
747+
self.proof.prior_loops_cache[curr_node.id] = prior_loops
748+
732749
_LOGGER.info(f'Prior loop heads for node {self.proof.id}: {(curr_node.id, prior_loops)}')
733750
if len(prior_loops) > self.proof.bmc_depth:
734751
_LOGGER.warning(f'Bounded node {self.proof.id}: {curr_node.id} at bmc depth {self.proof.bmc_depth}')

0 commit comments

Comments
 (0)