@@ -80,6 +80,7 @@ class APRProof(Proof, KCFGExploration):
80
80
circularity : bool
81
81
_exec_time : float
82
82
error_info : Exception | None
83
+ prior_loops_cache : dict [int , list [int ]]
83
84
84
85
def __init__ (
85
86
self ,
@@ -98,6 +99,7 @@ def __init__(
98
99
admitted : bool = False ,
99
100
_exec_time : float = 0 ,
100
101
error_info : Exception | None = None ,
102
+ prior_loops_cache : dict [int , list [int ]] | None = None ,
101
103
):
102
104
Proof .__init__ (self , id , proof_dir = proof_dir , subproof_ids = subproof_ids , admitted = admitted )
103
105
KCFGExploration .__init__ (self , kcfg , terminal )
@@ -110,6 +112,7 @@ def __init__(
110
112
self .logs = logs
111
113
self .circularity = circularity
112
114
self .node_refutations = {}
115
+ self .prior_loops_cache = prior_loops_cache if prior_loops_cache is not None else {}
113
116
self .kcfg ._kcfg_store = KCFGStore (self .proof_subdir / 'kcfg' ) if self .proof_subdir else None
114
117
self ._exec_time = _exec_time
115
118
self .error_info = error_info
@@ -201,6 +204,12 @@ def prune(self, node_id: NodeIdLike, keep_nodes: Iterable[NodeIdLike] = ()) -> l
201
204
pruned_nodes = super ().prune (node_id , keep_nodes = list (keep_nodes ) + [self .init , self .target ])
202
205
for nid in pruned_nodes :
203
206
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
+
204
213
return pruned_nodes
205
214
206
215
@property
@@ -481,6 +490,8 @@ def read_proof_data(proof_dir: Path, id: str) -> APRProof:
481
490
kcfg ._resolve (int (node_id )): proof_id for node_id , proof_id in proof_dict ['node_refutations' ].items ()
482
491
}
483
492
493
+ prior_loops_cache = {int (k ): v for k , v in proof_dict .get ('loops_cache' , {}).items ()}
494
+
484
495
return APRProof (
485
496
id = id ,
486
497
kcfg = kcfg ,
@@ -495,6 +506,7 @@ def read_proof_data(proof_dir: Path, id: str) -> APRProof:
495
506
proof_dir = proof_dir ,
496
507
subproof_ids = subproof_ids ,
497
508
node_refutations = node_refutations ,
509
+ prior_loops_cache = prior_loops_cache ,
498
510
_exec_time = exec_time ,
499
511
)
500
512
@@ -526,6 +538,8 @@ def write_proof_data(self) -> None:
526
538
if self .bmc_depth is not None :
527
539
dct ['bmc_depth' ] = self .bmc_depth
528
540
541
+ dct ['loops_cache' ] = self .prior_loops_cache
542
+
529
543
proof_json .write_text (json .dumps (dct ))
530
544
_LOGGER .info (f'Wrote proof data for { self .id } : { proof_json } ' )
531
545
self .kcfg .write_cfg_data ()
@@ -717,18 +731,21 @@ def step_proof(self) -> Iterable[StepResult]:
717
731
if self .proof .bmc_depth is not None and curr_node .id not in self ._checked_for_bounded :
718
732
_LOGGER .info (f'Checking bmc depth for node { self .proof .id } : { curr_node .id } ' )
719
733
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
+
732
749
_LOGGER .info (f'Prior loop heads for node { self .proof .id } : { (curr_node .id , prior_loops )} ' )
733
750
if len (prior_loops ) > self .proof .bmc_depth :
734
751
_LOGGER .warning (f'Bounded node { self .proof .id } : { curr_node .id } at bmc depth { self .proof .bmc_depth } ' )
0 commit comments