@@ -39,13 +39,11 @@ bool IsQuerySatisfiedHelper(const Query& query, const TTA& state) {
3939 case NodeType_t::CompEq:
4040 case NodeType_t::CompGreater:
4141 case NodeType_t::CompGreaterEq: {
42- std::string exprstring{}; // This string can technically be precompiled.
43- query.children [0 ].tree_apply ([&exprstring]( const ASTNode& node ){ exprstring += node.token ; });
44- exprstring += query.root .token ;
45- query.children [1 ].tree_apply ([&exprstring]( const ASTNode& node ){ exprstring += node.token ; });
46- spdlog::debug (" Assembled expression '{0}'" , exprstring);
47- calculator c (exprstring.c_str ());
48- return c.eval (state.GetSymbols ()).asBool ();
42+ std::stringstream exprstring{}; // This string can technically be precompiled.
43+ query.children [0 ].tree_apply ([&exprstring]( const ASTNode& node ){ exprstring << node.token ; });
44+ exprstring << query.root .token ;
45+ query.children [1 ].tree_apply ([&exprstring]( const ASTNode& node ){ exprstring << node.token ; });
46+ return calculator (exprstring.str ().c_str ()).eval (state.GetSymbols ()).asBool ();
4947 }
5048 case NodeType_t::SubExpr:
5149 case NodeType_t::Finally:
@@ -66,9 +64,7 @@ bool IsQuerySatisfiedHelper(const Query& query, const TTA& state) {
6664
6765bool ReachabilitySearcher::IsQuerySatisfied (const Query& query, const TTA &state) {
6866 if (query.root .type == NodeType_t::Forall && query.children .begin ()->root .type == NodeType_t::Globally) {
69- auto invertedQ = Query (ASTNode{NodeType_t::Negation, " !" });
70- invertedQ.insert (query);
71- return IsQuerySatisfiedHelper (invertedQ, state);
67+ return !IsQuerySatisfiedHelper (query, state);
7268 }
7369 if (query.root .type != NodeType_t::Exists) {
7470 spdlog::critical (" Only reachability queries are supported right now, sorry." );
@@ -96,17 +92,22 @@ void ReachabilitySearcher::OutputResults(const std::vector<QueryResultPair>& res
9692 if (CLIConfig::getInstance ()[" output" ]) {
9793 std::ofstream outputFile{CLIConfig::getInstance ()[" output" ].as_string (), std::ofstream::trunc};
9894 for (auto & r : results) {
99- outputFile << ConvertASTToString (*r.query ) << " : " << std::boolalpha << r.answer << " \n " ;
95+ auto answer = r.query ->root .type == NodeType_t::Forall && r.query ->children [0 ].root .type == NodeType_t::Globally ? !r.answer : r.answer ;
96+ outputFile << ConvertASTToString (*r.query ) << " : " << std::boolalpha << answer << " \n " ;
10097 }
10198 }
10299}
103100
104- void ReachabilitySearcher::PrintResults (const std::vector<QueryResultPair>& results) {
101+ auto ReachabilitySearcher::PrintResults (const std::vector<QueryResultPair>& results) -> int {
105102 OutputResults (results);
103+ auto acceptedResults = 0 ;
106104 spdlog::info (" ==== QUERY RESULTS ====" );
107105 for (const auto & r : results) {
108106 spdlog::info (" ====================" ); // Delimiter to make it easier to read
109- spdlog::info (" {0} : {1}" , ConvertASTToString (*r.query ), r.answer );
107+ auto answer = r.query ->root .type == NodeType_t::Forall && r.query ->children [0 ].root .type == NodeType_t::Globally ? !r.answer : r.answer ;
108+ if (answer)
109+ acceptedResults++;
110+ spdlog::info (" {0} : {1}" , ConvertASTToString (*r.query ), answer);
110111 auto stateHash = r.acceptingStateHash ;
111112 auto state = r.acceptingState ;
112113 std::vector<std::string> trace{};
@@ -135,13 +136,18 @@ void ReachabilitySearcher::PrintResults(const std::vector<QueryResultPair>& resu
135136 break ;
136137 }
137138 }
139+ if (trace.empty ()) {
140+ spdlog::info (" No trace available" );
141+ continue ;
142+ }
138143 spdlog::info (" Trace:" );
139144 std::reverse (trace.begin (), trace.end ());
140- printf (" [" );
145+ printf (" [\n " );
141146 for (auto & stateStr : trace)
142147 printf (" %s,\n " , stateStr.c_str ());
143148 printf (" ]\n " );
144149 }
150+ return acceptedResults;
145151}
146152
147153auto debug_int_as_hex_str (size_t v) {
@@ -150,17 +156,32 @@ auto debug_int_as_hex_str(size_t v) {
150156 return std::string (buffer);
151157}
152158
159+ std::string debug_get_current_state_string_human (const TTA& tta) {
160+ std::stringstream ss{};
161+ for (auto & c : tta.components )
162+ ss << c.second .currentLocation .identifier << " , " ;
163+ return ss.str ();
164+ }
165+
153166void debug_print_passed_list (const ReachabilitySearcher& r) {
154167 spdlog::trace (" ==== PASSED LIST ====" );
155168 for (auto & e : r.Passed ) {
156- spdlog::trace (" Hash:{0} Prev:{1}" ,
169+ if (e.first == e.second .prevStateHash ) {
170+ spdlog::warn (" Hash:{0} Prev:{1} \t State:{2}" ,
171+ debug_int_as_hex_str (e.first ),
172+ debug_int_as_hex_str (e.second .prevStateHash ),
173+ debug_get_current_state_string_human (e.second .tta ));
174+ continue ;
175+ }
176+ spdlog::trace (" Hash:{0} Prev:{1} \t State:{2}" ,
157177 debug_int_as_hex_str (e.first ),
158- debug_int_as_hex_str (e.second .prevStateHash ));
178+ debug_int_as_hex_str (e.second .prevStateHash ),
179+ debug_get_current_state_string_human (e.second .tta ));
159180 }
160181 spdlog::trace (" ====/PASSED LIST ====" );
161182}
162183
163- void debug_cleanup_waiting_list (ReachabilitySearcher& s, size_t curstatehash, const SearchState& state) {
184+ void cleanup_waiting_list (ReachabilitySearcher& s, size_t curstatehash, const SearchState& state) {
164185 bool found;
165186 do {
166187 found = false ;
@@ -175,6 +196,13 @@ void debug_cleanup_waiting_list(ReachabilitySearcher& s, size_t curstatehash, co
175196 } while (found);
176197}
177198
199+ std::string debug_get_symbol_map_string_representation (const TTA::SymbolMap& map) {
200+ std::ostringstream ss{};
201+ for (auto & symbol : map.map ())
202+ ss << symbol.first << " :-> " << symbol.second << " , " ;
203+ return ss.str ();
204+ }
205+
178206bool ReachabilitySearcher::ForwardReachabilitySearch (const nondeterminism_strategy_t & strategy) {
179207 auto stateit = Waiting.begin ();
180208 while (stateit != Waiting.end ()) {
@@ -183,9 +211,11 @@ bool ReachabilitySearcher::ForwardReachabilitySearch(const nondeterminism_strate
183211 AreQueriesSatisfied (query_results, state.tta , curstatehash);
184212 if (AreQueriesAnswered (query_results)) {
185213 Passed.emplace (std::make_pair (curstatehash, state));
186- if (! CLIConfig::getInstance ()[" notrace " ] )
187- PrintResults (query_results );
214+ if (CLIConfig::getInstance ()[" verbosity " ] && CLIConfig::getInstance ()[ " verbosity " ]. as_integer () >= 6 )
215+ debug_print_passed_list (* this );
188216 spdlog::info (" Found a positive result after searching: {0} states" , Passed.size ());
217+ if (!CLIConfig::getInstance ()[" notrace" ])
218+ return query_results.size () - PrintResults (query_results) == 0 ;
189219 return true ; // All the queries has been reached
190220 }
191221 // If the state is interesting, apply tock changes
@@ -198,14 +228,15 @@ bool ReachabilitySearcher::ForwardReachabilitySearch(const nondeterminism_strate
198228 AddToWaitingList (state.tta , allTickStateChanges, false , curstatehash);
199229
200230 Passed.emplace (std::make_pair (curstatehash, state));
201- debug_cleanup_waiting_list (*this , curstatehash, state);
231+
232+ cleanup_waiting_list (*this , curstatehash, state);
202233 stateit = PickStateFromWaitingList (strategy);
203234 }
204- if (!CLIConfig::getInstance ()[" notrace" ])
205- PrintResults (query_results);
206235 spdlog::info (" Found a negative result after searching: {0} states" , Passed.size ());
207236 if (CLIConfig::getInstance ()[" verbosity" ].as_integer () >= 6 )
208237 debug_print_passed_list (*this );
238+ if (!CLIConfig::getInstance ()[" notrace" ])
239+ return query_results.size () - PrintResults (query_results) == 0 ;
209240 return false ;
210241}
211242
@@ -228,8 +259,10 @@ void ReachabilitySearcher::AddToWaitingList(const TTA &state, const std::vector<
228259 auto nstate = state << change;
229260 auto nstatehash = nstate.GetCurrentStateHash ();
230261 if (Passed.find (nstatehash) == Passed.end ()) {
231- if (nstatehash == state_hash)
232- spdlog::warn (" Colliding state hashes!" );
262+ if (nstatehash == state_hash) {
263+ spdlog::warn (" Recursive state hashes!" );
264+ continue ;
265+ }
233266 Waiting.emplace (std::make_pair (nstatehash, SearchState{nstate, state_hash, justTocked}));
234267 }
235268 }
@@ -238,12 +271,16 @@ void ReachabilitySearcher::AddToWaitingList(const TTA &state, const std::vector<
238271 if (statechanges.size () > 1 ) {
239272 auto baseChanges = state << *statechanges.begin ();
240273 for (auto it = statechanges.begin () + 1 ; it != statechanges.end (); ++it) {
274+ if (it->IsEmpty ())
275+ continue ;
241276 // / This is a lot of copying large data objects... Figure something out with maybe std::move
242277 auto nstate = baseChanges << *it;
243278 auto nstatehash = nstate.GetCurrentStateHash ();
244279 if (Passed.find (nstatehash) == Passed.end ()) {
245- if (nstatehash == state_hash)
246- spdlog::warn (" Colliding state hashes!" );
280+ if (nstatehash == state_hash) {
281+ spdlog::warn (" Recursive state hashes!" );
282+ continue ;
283+ }
247284 Waiting.emplace (std::make_pair (nstatehash, SearchState{nstate, state_hash, justTocked}));
248285 }
249286 }
0 commit comments