19
19
from ..prelude .ml import mlAnd , mlTop
20
20
from ..utils import FrozenDict , ensure_dir_path , hash_str , shorten_hashes , single
21
21
from .implies import ProofSummary , Prover , RefutationProof
22
- from .proof import CompositeSummary , FailureInfo , Proof , ProofStatus , StepResult
22
+ from .proof import CompositeSummary , FailureInfo , Proof , ProofStatus , ProofStep , StepResult
23
23
24
24
if TYPE_CHECKING :
25
25
from collections .abc import Iterable , Mapping
@@ -59,6 +59,12 @@ class APRProofTerminalResult(APRProofResult): ...
59
59
class APRProofBoundedResult (APRProofResult ): ...
60
60
61
61
62
+ @dataclass
63
+ class APRProofStep (ProofStep ):
64
+ proof : APRProof
65
+ node_id : int
66
+
67
+
62
68
class APRProof (Proof , KCFGExploration ):
63
69
"""APRProof and APRProver implement all-path reachability logic,
64
70
as introduced by A. Stefanescu and others in their paper 'All-Path Reachability Logic':
@@ -132,6 +138,9 @@ def __init__(
132
138
assert type (subproof ) is RefutationProof
133
139
self .node_refutations [node_id ] = subproof
134
140
141
+ def get_steps (self ) -> Iterable [APRProofStep ]:
142
+ return [APRProofStep (self , node .id ) for node in self .pending ]
143
+
135
144
def commit (self , result : StepResult ) -> None :
136
145
if isinstance (result , APRProofExtendResult ):
137
146
self .kcfg .extend (result .extend_result , self .kcfg .node (result .node_id ), logs = self .logs )
@@ -720,37 +729,37 @@ def _check_subsume(self, node: KCFG.Node) -> CSubst | None:
720
729
_LOGGER .info (f'Subsumed into target node { self .proof .id } : { shorten_hashes ((node .id , self .proof .target ))} ' )
721
730
return csubst
722
731
723
- def step_proof (self ) -> Iterable [StepResult ]:
724
- if not self . proof . pending :
725
- return []
726
- curr_node = self .proof .pending [ 0 ]
732
+ def step_proof (self , step : ProofStep ) -> Iterable [StepResult ]:
733
+ assert isinstance ( step , APRProofStep )
734
+
735
+ curr_node = step .proof .kcfg . node ( step . node_id )
727
736
728
- if self .proof .bmc_depth is not None and curr_node .id not in self ._checked_for_bounded :
729
- _LOGGER .info (f'Checking bmc depth for node { self .proof .id } : { curr_node .id } ' )
737
+ if step .proof .bmc_depth is not None and curr_node .id not in self ._checked_for_bounded :
738
+ _LOGGER .info (f'Checking bmc depth for node { step .proof .id } : { curr_node .id } ' )
730
739
self ._checked_for_bounded .add (curr_node .id )
731
740
732
741
prior_loops = []
733
- for succ in reversed (self .proof .shortest_path_to (curr_node .id )):
742
+ for succ in reversed (step .proof .shortest_path_to (curr_node .id )):
734
743
if self .kcfg_explore .kcfg_semantics .same_loop (succ .source .cterm , curr_node .cterm ):
735
- if succ .source .id in self .proof .prior_loops_cache :
736
- if self .proof .kcfg .zero_depth_between (succ .source .id , curr_node .id ):
737
- prior_loops = self .proof .prior_loops_cache [succ .source .id ]
744
+ if succ .source .id in step .proof .prior_loops_cache :
745
+ if step .proof .kcfg .zero_depth_between (succ .source .id , curr_node .id ):
746
+ prior_loops = step .proof .prior_loops_cache [succ .source .id ]
738
747
else :
739
- prior_loops = self .proof .prior_loops_cache [succ .source .id ] + [succ .source .id ]
748
+ prior_loops = step .proof .prior_loops_cache [succ .source .id ] + [succ .source .id ]
740
749
break
741
750
else :
742
- self .proof .prior_loops_cache [succ .source .id ] = []
751
+ step .proof .prior_loops_cache [succ .source .id ] = []
743
752
744
- self .proof .prior_loops_cache [curr_node .id ] = prior_loops
753
+ step .proof .prior_loops_cache [curr_node .id ] = prior_loops
745
754
746
- _LOGGER .info (f'Prior loop heads for node { self .proof .id } : { (curr_node .id , prior_loops )} ' )
747
- if len (prior_loops ) > self .proof .bmc_depth :
748
- _LOGGER .warning (f'Bounded node { self .proof .id } : { curr_node .id } at bmc depth { self .proof .bmc_depth } ' )
755
+ _LOGGER .info (f'Prior loop heads for node { step .proof .id } : { (curr_node .id , prior_loops )} ' )
756
+ if len (prior_loops ) > step .proof .bmc_depth :
757
+ _LOGGER .warning (f'Bounded node { step .proof .id } : { curr_node .id } at bmc depth { step .proof .bmc_depth } ' )
749
758
return [APRProofBoundedResult (curr_node .id )]
750
759
751
760
# Terminal checks for current node and target node
752
761
is_terminal = self .kcfg_explore .kcfg_semantics .is_terminal (curr_node .cterm )
753
- target_is_terminal = self .proof .is_terminal (self .proof .target )
762
+ target_is_terminal = step .proof .is_terminal (step .proof .target )
754
763
755
764
terminal_result = [APRProofTerminalResult (node_id = curr_node .id )] if is_terminal else []
756
765
@@ -768,7 +777,7 @@ def step_proof(self) -> Iterable[StepResult]:
768
777
769
778
module_name = self .circularities_module_name if self .nonzero_depth (curr_node ) else self .dependencies_module_name
770
779
771
- self .kcfg_explore .check_extendable (self .proof , curr_node )
780
+ self .kcfg_explore .check_extendable (step .proof , curr_node )
772
781
extend_result = self .kcfg_explore .extend_cterm (
773
782
curr_node .cterm ,
774
783
execute_depth = self .execute_depth ,
0 commit comments