8
8
from pyk .kore .rpc import LogEntry
9
9
10
10
from ..cterm import CTerm
11
- from ..kast .inner import KRewrite , KSort
11
+ from ..kast .inner import KInner , KRewrite , KSort , Subst
12
12
from ..kast .manip import flatten_label , ml_pred_to_bool
13
13
from ..kast .outer import KClaim
14
14
from ..kcfg import KCFG
23
23
from pathlib import Path
24
24
from typing import Any , Final , TypeVar
25
25
26
- from ..kast .inner import KInner
27
26
from ..kast .outer import KDefinition
28
27
from ..kcfg import KCFGExplore
29
28
from ..kcfg .kcfg import NodeIdLike
@@ -781,27 +780,61 @@ def lines(self) -> list[str]:
781
780
782
781
@dataclass (frozen = True )
783
782
class APRFailureInfo :
784
- failing_nodes : FrozenDict [int , tuple [str , str ]]
785
783
pending_nodes : frozenset [int ]
784
+ failing_nodes : frozenset [int ]
785
+ path_conditions : FrozenDict [int , str ]
786
+ failure_reasons : FrozenDict [int , str ]
787
+ models : FrozenDict [int , frozenset [tuple [str , str ]]]
786
788
787
- def __init__ (self , failing_nodes : Mapping [int , tuple [str , str ]], pending_nodes : Iterable [int ]):
788
- object .__setattr__ (self , 'failing_nodes' , FrozenDict (failing_nodes ))
789
+ def __init__ (
790
+ self ,
791
+ failing_nodes : Iterable [int ],
792
+ pending_nodes : Iterable [int ],
793
+ path_conditions : Mapping [int , str ],
794
+ failure_reasons : Mapping [int , str ],
795
+ models : Mapping [int , Iterable [tuple [str , str ]]],
796
+ ):
797
+ object .__setattr__ (self , 'failing_nodes' , frozenset (failing_nodes ))
789
798
object .__setattr__ (self , 'pending_nodes' , frozenset (pending_nodes ))
799
+ object .__setattr__ (self , 'path_conditions' , FrozenDict (path_conditions ))
800
+ object .__setattr__ (self , 'failure_reasons' , FrozenDict (failure_reasons ))
801
+ object .__setattr__ (
802
+ self , 'models' , FrozenDict ({node_id : frozenset (model ) for (node_id , model ) in models .items ()})
803
+ )
790
804
791
805
@staticmethod
792
- def from_proof (proof : APRProof , kcfg_explore : KCFGExplore ) -> APRFailureInfo :
806
+ def from_proof (proof : APRProof , kcfg_explore : KCFGExplore , counterexample_info : bool = False ) -> APRFailureInfo :
793
807
target = proof .kcfg .node (proof .target )
794
808
pending_nodes = {node .id for node in proof .pending }
795
- failing_nodes = {}
809
+ failing_nodes = {node .id for node in proof .failing }
810
+ path_conditions = {}
811
+ failure_reasons = {}
812
+ models = {}
796
813
for node in proof .failing :
797
814
simplified_node , _ = kcfg_explore .cterm_simplify (node .cterm )
798
815
simplified_target , _ = kcfg_explore .cterm_simplify (target .cterm )
799
816
node_cterm = CTerm .from_kast (simplified_node )
800
817
target_cterm = CTerm .from_kast (simplified_target )
801
818
_ , reason = kcfg_explore .implication_failure_reason (node_cterm , target_cterm )
802
819
path_condition = kcfg_explore .kprint .pretty_print (proof .path_constraints (node .id ))
803
- failing_nodes [node .id ] = (reason , path_condition )
804
- return APRFailureInfo (failing_nodes = failing_nodes , pending_nodes = pending_nodes )
820
+ failure_reasons [node .id ] = reason
821
+ path_conditions [node .id ] = path_condition
822
+ if counterexample_info :
823
+ model_subst = kcfg_explore .cterm_get_model (node .cterm )
824
+ if type (model_subst ) is Subst :
825
+ model : list [tuple [str , str ]] = []
826
+ for var , term in model_subst .to_dict ().items ():
827
+ term_kast = KInner .from_dict (term )
828
+ term_pretty = kcfg_explore .kprint .pretty_print (term_kast )
829
+ model .append ((var , term_pretty ))
830
+ models [node .id ] = model
831
+ return APRFailureInfo (
832
+ failing_nodes = failing_nodes ,
833
+ pending_nodes = pending_nodes ,
834
+ path_conditions = path_conditions ,
835
+ failure_reasons = failure_reasons ,
836
+ models = models ,
837
+ )
805
838
806
839
def print (self ) -> list [str ]:
807
840
res_lines : list [str ] = []
@@ -819,10 +852,9 @@ def print(self) -> list[str]:
819
852
if num_failing > 0 :
820
853
res_lines .append ('' )
821
854
res_lines .append ('Failing nodes:' )
822
- print (self .failing_nodes )
823
- for node_id , info in self .failing_nodes .items ():
824
- print (info )
825
- (reason , path_condition ) = info
855
+ for node_id in self .failing_nodes :
856
+ reason = self .failure_reasons [node_id ]
857
+ path_condition = self .path_conditions [node_id ]
826
858
res_lines .append ('' )
827
859
res_lines .append (f' Node id: { str (node_id )} ' )
828
860
@@ -832,6 +864,13 @@ def print(self) -> list[str]:
832
864
res_lines .append (' Path condition:' )
833
865
res_lines += [f' { path_condition } ' ]
834
866
867
+ if node_id in self .models :
868
+ res_lines .append (' Model:' )
869
+ for var , term in self .models [node_id ]:
870
+ res_lines .append (f' { var } = { term } ' )
871
+ else :
872
+ res_lines .append (' Failed to generate a model.' )
873
+
835
874
res_lines .append ('' )
836
875
res_lines .append ('Join the Runtime Verification Discord server for support: https://discord.gg/CurfmXNtbN' )
837
876
return res_lines
0 commit comments