1- from itertools import chain , tee
1+ from itertools import chain , product
22
33from aalpy .base .Oracle import Oracle
44from aalpy .base .SUL import SUL
5- from aalpy .utils .HelperFunctions import product_with_possible_empty_iterable
65
76
87def state_characterization_set (hypothesis , alphabet , state ):
@@ -23,34 +22,45 @@ def state_characterization_set(hypothesis, alphabet, state):
2322 return result
2423
2524
26- def i_star (alphabet , max_seq_len ):
25+ def first_phase_it (alphabet , state_cover , depth , char_set ):
2726 """
28- Return an iterator that generates all possible sequences of length upto from the given alphabet .
27+ Return an iterator that generates all possible sequences for the first phase of the Wp-method .
2928 Args:
3029 alphabet: input alphabet
31- max_seq_len: maximum length of the sequences
30+ state_cover: list of states to cover
31+ depth: maximum length of middle part
32+ char_set: characterization set
3233 """
33- return chain (* (product_with_possible_empty_iterable (alphabet , repeat = i ) for i in range (max_seq_len )))
34+ char_set = char_set or [()]
35+ for d in range (depth ):
36+ middle = product (alphabet , repeat = d )
37+ for m in middle :
38+ for s in state_cover :
39+ for c in char_set :
40+ yield s + m + c
3441
3542
36- def second_phase_test_case_generator (hyp , alphabet , difference , middle ):
43+ def second_phase_it (hyp , alphabet , difference , depth ):
3744 """
3845 Return an iterator that generates all possible sequences for the second phase of the Wp-method.
3946 Args:
4047 hyp: hypothesis automaton
4148 alphabet: input alphabet
4249 difference: set of sequences that are in the transition cover but not in the state cover
43- middle: iterator that generates all possible sequences of length upto from the given alphabet
50+ depth: maximum length of middle part
4451 """
4552 state_mapping = {}
46- for t , mid in product_with_possible_empty_iterable (difference , middle ):
47- _ = hyp .execute_sequence (hyp .initial_state , t + mid )
48- state = hyp .current_state
49- if state not in state_mapping :
50- state_mapping [state ] = state_characterization_set (hyp , alphabet , state )
53+ for d in range (depth ):
54+ middle = product (alphabet , repeat = d )
55+ for mid in middle :
56+ for t in difference :
57+ _ = hyp .execute_sequence (hyp .initial_state , t + mid )
58+ state = hyp .current_state
59+ if state not in state_mapping :
60+ state_mapping [state ] = state_characterization_set (hyp , alphabet , state )
5161
52- for sm in state_mapping [state ]:
53- yield t + mid + sm
62+ for sm in state_mapping [state ]:
63+ yield t + mid + sm
5464
5565
5666class WpMethodEqOracle (Oracle ):
@@ -63,21 +73,6 @@ def __init__(self, alphabet: list, sul: SUL, max_number_of_states=4):
6373 self .m = max_number_of_states
6474 self .cache = set ()
6575
66- def test_sequance (self , hypothesis , seq_under_test ):
67- self .reset_hyp_and_sul (hypothesis )
68-
69- for ind , letter in enumerate (seq_under_test ):
70- out_hyp = hypothesis .step (letter )
71- out_sul = self .sul .step (letter )
72- self .num_steps += 1
73-
74- if out_hyp != out_sul :
75- self .sul .post ()
76- return seq_under_test [: ind + 1 ]
77- self .cache .add (seq_under_test )
78-
79- return None
80-
8176 def find_cex (self , hypothesis ):
8277 if not hypothesis .characterization_set :
8378 hypothesis .characterization_set = hypothesis .compute_characterization_set ()
@@ -90,31 +85,27 @@ def find_cex(self, hypothesis):
9085
9186 state_cover = set (state .prefix for state in hypothesis .states )
9287 difference = transition_cover .difference (state_cover )
93-
94- # two views of the same iterator
95- middle_1 , middle_2 = tee (i_star (self .alphabet , self .m - hypothesis .size + 1 ), 2 )
96-
88+ depth = self .m + 1 - len (hypothesis .states )
9789 # first phase State Cover * Middle * Characterization Set
98- state_cover = state_cover or [()]
99- char_set = hypothesis .characterization_set or [()]
100-
101- for sc in state_cover :
102- for m in middle_1 :
103- for cs in char_set :
104- test_seq = sc + m + cs
105- if test_seq not in self .cache :
106- counterexample = self .test_sequance (hypothesis , test_seq )
107- if counterexample :
108- return counterexample
90+ first_phase = first_phase_it (self .alphabet , state_cover , depth , hypothesis .characterization_set )
10991
11092 # second phase (Transition Cover - State Cover) * Middle * Characterization Set
11193 # of the state that the prefix leads to
112- second_phase = second_phase_test_case_generator (hypothesis , self .alphabet , difference , middle_2 )
113-
114- for test_seq in second_phase :
115- if test_seq not in self .cache :
116- counterexample = self .test_sequance (hypothesis , test_seq )
117- if counterexample :
118- return counterexample
94+ second_phase = second_phase_it (hypothesis , self .alphabet , difference , depth )
95+ test_suite = chain (first_phase , second_phase )
96+
97+ for seq in test_suite :
98+ if seq not in self .cache :
99+ self .reset_hyp_and_sul (hypothesis )
100+
101+ for ind , letter in enumerate (seq ):
102+ out_hyp = hypothesis .step (letter )
103+ out_sul = self .sul .step (letter )
104+ self .num_steps += 1
105+
106+ if out_hyp != out_sul :
107+ self .sul .post ()
108+ return seq [: ind + 1 ]
109+ self .cache .add (seq )
119110
120111 return None
0 commit comments