Skip to content

Commit dca1412

Browse files
authored
Merge pull request #34 from sillydan1/patch/bugfixes
2 parents cfe2a4a + 7fa2f3d commit dca1412

File tree

9 files changed

+210
-73
lines changed

9 files changed

+210
-73
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
# 3.16+ because of target_precompiled_header
1818
cmake_minimum_required(VERSION 3.16)
19-
project(aaltitoad VERSION 0.9.2)
19+
project(aaltitoad VERSION 0.10.0)
2020
configure_file(src/config.h.in config.h)
2121
set(THREADS_PREFER_PTHREAD_FLAG ON)
2222
find_package(Threads REQUIRED)

src/cli/CLIConfig.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ CLIConfig::CLIConfig() {
2727
{ option_requirement::Optional,
2828
{"output", 'o', argument_requirement::REQUIRE_ARG,
2929
"[DIR]/[FILENAME] Output file. Will be created, if not already exists"} },
30+
{ option_requirement::Optional,
31+
{"immediate-output", '!', argument_requirement::NO_ARG,
32+
"Immediately output a trace once a query has been satisfied"} },
3033
{ option_requirement::Optional,
3134
{"query", 'q', argument_requirement::REQUIRE_ARG,
3235
"[DIR]/[FILENAME] File with queries to be verified. This flag is required for verification"} },
@@ -60,6 +63,9 @@ CLIConfig::CLIConfig() {
6063
{ option_requirement::Optional,
6164
{"notrace", 'c', argument_requirement::NO_ARG,
6265
"Disable print of traces to stdout"} },
66+
{ option_requirement::Optional,
67+
{"print-memory", 'g', argument_requirement::REQUIRE_ARG,
68+
"[INTEGER] Periodically print (debug level) current searchspace size"} },
6369
};
6470
status_code = EXIT_SUCCESS;
6571
}

src/model_parsers/TTAParser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ std::vector<std::string> componentIgnoreList = { // NOLINT(cert-err58-cpp)
2828
"ignore", // ignore all files that want to be ignored
2929
"Queries.json", // Queries are not component- or symbol-files
3030
".parts", // parts files are not components
31+
".DS_Store", // OSX makes these files all the time.
3132
};
3233

3334
bool ShouldSkipEntry(const std::filesystem::directory_entry& entry) {

src/runtime/TTA.cpp

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,35 @@
2222
#include <tinytimer/Timer.hpp>
2323
#include <verifier/trace_output/TTAResugarizer.h>
2424

25+
auto TTA::operator==(const TTA &other) -> bool {
26+
for(auto& c : components) {
27+
if(c.second.currentLocation.identifier != other.components.at(c.first).currentLocation.identifier)
28+
return false;
29+
}
30+
for(auto& s : symbols.map()) {
31+
if(s.second != other.symbols.map()[s.first])
32+
return false;
33+
}
34+
return true;
35+
}
36+
37+
auto TTA::operator!=(const TTA &other) -> bool {
38+
return !(*this == other);
39+
}
40+
2541
TTA::StateChange operator+(TTA::StateChange a, TTA::StateChange b) {
2642
// Merge a and b
27-
a.symbols.map().merge(b.symbols.map());
28-
a.componentLocations.merge(b.componentLocations);
29-
return a;
43+
// a.symbols.map().merge(b.symbols.map());
44+
TTA::StateChange cpy{};
45+
for(auto& s : a.symbols.map())
46+
cpy.symbols[s.first] = s.second;
47+
for(auto& s : b.symbols.map())
48+
cpy.symbols[s.first] = s.second;
49+
for(auto& c : a.componentLocations)
50+
cpy.componentLocations[c.first] = c.second;
51+
for(auto& c : b.componentLocations)
52+
cpy.componentLocations[c.first] = c.second;
53+
return cpy;
3054
}
3155

3256
TTA operator<<(const TTA& aa, const TTA::StateChange& b) {
@@ -168,33 +192,31 @@ bool TTA::SetComponentLocations(const ComponentLocationMap &locationChange) {
168192
bool TTA::SetSymbols(const SymbolMap &symbolChange) {
169193
for(auto& symbol : symbolChange.map()) {
170194
auto symbolit = symbols.map().find(symbol.first);
171-
bool noerror = TypeCheck(symbol, symbolit);
172-
if(noerror) {
173-
symbols.map()[symbol.first] = symbol.second;
174-
if(externalSymbols.find(symbol.first) != externalSymbols.end())
175-
externalSymbols[symbol.first] = symbols.find(symbol.first);
176-
}
177-
else return false;
195+
if(!TypeCheck(symbol, symbolit))
196+
return false;
197+
symbols.map()[symbol.first] = symbol.second;
198+
if(externalSymbols.find(symbol.first) != externalSymbols.end())
199+
externalSymbols[symbol.first] = symbols.find(symbol.first);
178200
}
179201
return true;
180202
}
181203

182204
bool TTA::TypeCheck(const std::pair<const std::string, packToken> &symbol,
183205
const std::map<std::string, packToken>::iterator &changingSymbol) const {
184-
auto x = symbol.second->type;
185-
auto y = changingSymbol->second->type;
186206
if(changingSymbol == symbols.map().end()) {
187207
spdlog::critical("Attempted to change the state of TTA failed. Symbol '{0}' does not exist.", symbol.first);
188208
return false;
189-
} else if(!(NUM & x & y) && !(x == VAR && (NUM & y))) {
190-
auto a = tokenTypeToString(changingSymbol->second->type);
191-
auto b = tokenTypeToString(symbol.second->type);
192-
spdlog::critical(
193-
"Attempted to change the state of TTA failed. Symbol '{0}' does not have the correct type. ({1} vs {2} (a := b))",
194-
symbol.first, a, b);
195-
return false;
196209
}
197-
return true;
210+
auto x = symbol.second->type;
211+
auto y = changingSymbol->second->type;
212+
if((NUM & x & y) || (x == VAR && (NUM & y)) || (x == y))
213+
return true;
214+
auto a = tokenTypeToString(changingSymbol->second->type);
215+
auto b = tokenTypeToString(symbol.second->type);
216+
spdlog::critical(
217+
"Attempted to change the state of TTA failed. Symbol '{0}' does not have the correct type. ({1} vs {2} (a := b))",
218+
symbol.first, a, b);
219+
return false;
198220
}
199221

200222
bool TTA::IsCurrentStateImmediate() const {
@@ -305,8 +327,12 @@ std::string TTA::GetCurrentStateString() const {
305327
std::stringstream ss{}; ss << "{";
306328
for(auto& component : components)
307329
ss<<"\""<<component.first<<"\""<<": "<<"\""<<component.second.currentLocation.identifier<<"\",";
308-
for(auto& symbol : symbols.map())
309-
ss<<"\""<<symbol.first<<"\""<<": "<<"\""<<symbol.second.str()<<"\",";
330+
for(auto& symbol : symbols.map()) {
331+
if(symbol.second->type == TIMER)
332+
ss << "\"" << symbol.first << "\"" << ": " << "\"" << symbol.second.asDouble() << "\",";
333+
else
334+
ss << "\"" << symbol.first << "\"" << ": " << "\"" << symbol.second.str() << "\",";
335+
}
310336
ss << R"("OBJECT_END":"true"})"; // This is just a bad way of ending a json object.
311337
return ss.str();
312338
}

src/runtime/TTA.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ struct TTA {
127127
TokenMap GetSymbolChangesAsMap(std::vector<UpdateExpression> &symbolChanges) const;
128128
void WarnAboutComponentOverlap(component_overlap_t& overlappingComponents) const;
129129
bool TypeCheck(const std::pair<const std::string, packToken> &symbol, const std::map<std::string, packToken>::iterator &changingSymbol) const;
130+
/// WARNING: Very expensive operation!
131+
auto operator==(const TTA& other) -> bool;
132+
auto operator!=(const TTA& other) -> bool;
130133
};
131134

132135
struct StateMultiChoice {

src/verifier/ReachabilitySearcher.cpp

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,19 @@ bool ReachabilitySearcher::IsQuerySatisfied(const Query& query, const TTA &state
7474
}
7575

7676
void ReachabilitySearcher::AreQueriesSatisfied(std::vector<QueryResultPair>& queries, const TTA& state, size_t state_hash) {
77-
for(auto & query : queries) {
78-
if(!query.answer) {
79-
query.answer = IsQuerySatisfied(*query.query, state);
80-
if (query.answer) {
81-
query.acceptingStateHash = state_hash;
82-
query.acceptingState.tta = state; // TODO: This is terrible
83-
auto ss = ConvertASTToString(*query.query);
84-
spdlog::info("Query '{0}' is satisfied!", ss);
85-
spdlog::debug("Query '{0}' was satisfied in state: \n{1}", ss, state.GetCurrentStateString());
86-
}
87-
}
77+
for(auto& query : queries) {
78+
if(query.answer)
79+
continue;
80+
if(!IsQuerySatisfied(*query.query, state))
81+
continue;
82+
query.answer = true;
83+
query.acceptingStateHash = state_hash;
84+
query.acceptingState.tta = state; // TODO: This is terrible
85+
auto ss = ConvertASTToString(*query.query);
86+
spdlog::info("Query '{0}' is satisfied!", ss);
87+
spdlog::debug("Query '{0}' was satisfied in state: \n{1}", ss, state.GetCurrentStateString());
88+
if(CLIConfig::getInstance()["immediate-output"])
89+
PrintResults({query});
8890
}
8991
}
9092

@@ -117,8 +119,21 @@ auto ReachabilitySearcher::PrintResults(const std::vector<QueryResultPair>& resu
117119
if(exists) {
118120
auto range = Passed.equal_range(stateHash);
119121
auto count = Passed.count(stateHash);
120-
if(count > 1)
121-
spdlog::warn("HASH COLLISIONS: {0}", count);
122+
if(count > 1) {
123+
std::stringstream ss{};
124+
int c = 0;
125+
for (auto it = range.first; it != range.second; ++it) {
126+
ss << it->second.tta.GetCurrentStateString();
127+
for(auto t = range.first; t != range.second; ++t) {
128+
if(it->second.tta != t->second.tta)
129+
c++;
130+
}
131+
}
132+
if(c > 0) {
133+
spdlog::warn("HASH COLLISIONS: {0}", c);
134+
spdlog::warn(ss.str());
135+
}
136+
}
122137

123138
if(stateHash == range.first->second.prevStateHash) {
124139
spdlog::critical("Breaking out of infinite loop. Something is wrong.");
@@ -127,10 +142,6 @@ auto ReachabilitySearcher::PrintResults(const std::vector<QueryResultPair>& resu
127142

128143
stateHash = range.first->second.prevStateHash;
129144
trace.push_back(range.first->second.tta.GetCurrentStateString());
130-
if(count > 1) {
131-
for (auto it = range.first; it != range.second; ++it)
132-
spdlog::warn(it->second.tta.GetCurrentStateString());
133-
}
134145
} else {
135146
spdlog::critical("Unable to resolve witnessing trace. ");
136147
break;
@@ -206,10 +217,19 @@ std::string debug_get_symbol_map_string_representation(const TTA::SymbolMap& map
206217

207218
bool ReachabilitySearcher::ForwardReachabilitySearch(const nondeterminism_strategy_t& strategy) {
208219
auto stateit = Waiting.begin();
220+
Timer<unsigned int> periodic_timer{};
221+
periodic_timer.start();
209222
while(stateit != Waiting.end()) {
223+
if(CLIConfig::getInstance()["print-memory"]) {
224+
if(periodic_timer.milliseconds_elapsed() >= CLIConfig::getInstance()["print-memory"].as_integer()) {
225+
spdlog::debug("Waiting list size: {0}", Waiting.size());
226+
periodic_timer.start();
227+
}
228+
}
229+
210230
auto& state = stateit->second;
211231
auto curstatehash = stateit->first;
212-
AreQueriesSatisfied(query_results, state.tta, curstatehash);
232+
213233
if(AreQueriesAnswered(query_results)) {
214234
Passed.emplace(std::make_pair(curstatehash, state));
215235
if(CLIConfig::getInstance()["verbosity"] && CLIConfig::getInstance()["verbosity"].as_integer() >= 6)
@@ -229,6 +249,7 @@ bool ReachabilitySearcher::ForwardReachabilitySearch(const nondeterminism_strate
229249
AddToWaitingList(state.tta, allTickStateChanges, false, curstatehash);
230250

231251
Passed.emplace(std::make_pair(curstatehash, state));
252+
AreQueriesSatisfied(query_results, state.tta, curstatehash);
232253

233254
cleanup_waiting_list(*this, curstatehash, state);
234255
stateit = PickStateFromWaitingList(strategy);
@@ -259,12 +280,22 @@ void ReachabilitySearcher::AddToWaitingList(const TTA &state, const std::vector<
259280
/// This is a lot of copying large data objects... Figure something out with maybe std::move
260281
auto nstate = state << change;
261282
auto nstatehash = nstate.GetCurrentStateHash();
262-
if (Passed.find(nstatehash) == Passed.end()) {
283+
auto passed_it = Passed.find(nstatehash);
284+
if (passed_it == Passed.end()) {
263285
if (nstatehash == state_hash) {
286+
if(nstate == state)
287+
continue;
264288
spdlog::warn("Recursive state hashes!");
265-
continue;
266289
}
267290
Waiting.emplace(std::make_pair(nstatehash, SearchState{nstate, state_hash, justTocked}));
291+
} else {
292+
auto r = Passed.equal_range(nstatehash);
293+
for(auto it = r.first; it != r.second; ++it) {
294+
if(nstate != it->second.tta) {
295+
Waiting.emplace(std::make_pair(nstatehash, SearchState{nstate, state_hash, justTocked}));
296+
break;
297+
}
298+
}
268299
}
269300
}
270301
}
@@ -277,12 +308,22 @@ void ReachabilitySearcher::AddToWaitingList(const TTA &state, const std::vector<
277308
/// This is a lot of copying large data objects... Figure something out with maybe std::move
278309
auto nstate = baseChanges << *it;
279310
auto nstatehash = nstate.GetCurrentStateHash();
280-
if (Passed.find(nstatehash) == Passed.end()) {
311+
auto passed_it = Passed.find(nstatehash);
312+
if (passed_it == Passed.end()) {
281313
if (nstatehash == state_hash) {
314+
if(nstate == state)
315+
continue;
282316
spdlog::warn("Recursive state hashes!");
283-
continue;
284317
}
285318
Waiting.emplace(std::make_pair(nstatehash, SearchState{nstate, state_hash, justTocked}));
319+
} else {
320+
auto r = Passed.equal_range(nstatehash);
321+
for(auto it = r.first; it != r.second; ++it) {
322+
if(nstate != it->second.tta) {
323+
Waiting.emplace(std::make_pair(nstatehash, SearchState{nstate, state_hash, justTocked}));
324+
break;
325+
}
326+
}
286327
}
287328
}
288329
}
@@ -293,9 +334,12 @@ bool ReachabilitySearcher::AreQueriesAnswered(const std::vector<QueryResultPair>
293334
}
294335

295336
bool ReachabilitySearcher::IsSearchStateTockable(const SearchState& state) {
296-
return (!state.justTocked && !state.tta.IsCurrentStateImmediate());
337+
return !state.justTocked
338+
&& !state.tta.IsCurrentStateImmediate();
297339
}
298340

341+
#include <random>
342+
std::random_device r;
299343
ReachabilitySearcher::StateList::iterator ReachabilitySearcher::PickStateFromWaitingList(const nondeterminism_strategy_t& strategy) {
300344
if(Waiting.empty())
301345
return Waiting.end();
@@ -309,14 +353,17 @@ ReachabilitySearcher::StateList::iterator ReachabilitySearcher::PickStateFromWai
309353
return Waiting.begin();
310354
case nondeterminism_strategy_t::PICK_LAST: {
311355
auto begin = Waiting.begin();
312-
for (auto i = 0; i < Waiting.size(); i++)
356+
for (auto i = 0; i < Waiting.size()-1; i++)
313357
begin++;
314358
return begin;
315359
}
316360
case nondeterminism_strategy_t::PICK_RANDOM:
317-
auto randomPick = rand() % Waiting.size();
361+
// auto randomPick = rand() % Waiting.size();
362+
std::default_random_engine e1(r());
363+
std::uniform_int_distribution<size_t> uniform_dist(0, Waiting.size()-1);
364+
auto randomPick = uniform_dist(e1);
318365
auto picked = Waiting.begin();
319-
for(int i = 0; i < randomPick; i++)
366+
for(auto i = 0; i < randomPick; i++)
320367
picked++;
321368
return picked;
322369
}

0 commit comments

Comments
 (0)