Skip to content
Snippets Groups Projects
Commit 167e8dfa authored by Cookiebowser's avatar Cookiebowser
Browse files

optimized c++ Template (MC)

parent 8a60d560
No related branches found
No related tags found
1 merge request!28Rust support
...@@ -137,7 +137,7 @@ P is a conjunction of n conjuncts where the i-th conjunct must constraint xi for ...@@ -137,7 +137,7 @@ P is a conjunction of n conjuncts where the i-th conjunct must constraint xi for
### Sets: ### Sets:
| Set expression or predicate | Meaining | | Set expression or predicate | Meaining |
|------------------------------|--------------------------------------------| |-------------------------------|--------------------------------------------|
| {} | Empty Set | | {} | Empty Set |
| {E} | Singleton Set | | {E} | Singleton Set |
| {E,F,...} | Set Enumeration | | {E,F,...} | Set Enumeration |
...@@ -159,8 +159,8 @@ P is a conjunction of n conjuncts where the i-th conjunct must constraint xi for ...@@ -159,8 +159,8 @@ P is a conjunction of n conjuncts where the i-th conjunct must constraint xi for
| S /<<: T | Not Strict Subset of | | S /<<: T | Not Strict Subset of |
| union(S) | Generalized Union over Sets of Sets | | union(S) | Generalized Union over Sets of Sets |
| inter(S) | Generalized Intersection over Sets of Sets | | inter(S) | Generalized Intersection over Sets of Sets |
| UNION(z1,...,zn).(P\|E) | Generalized Union with Predicate | | UNION(z1,...,zn).(P &#124; E) | Generalized Union with Predicate |
| INTER(z1,...,zn).(P\|E) | Generalized Intersection with Predicate | | INTER(z1,...,zn).(P &#124; E) | Generalized Intersection with Predicate |
Restriction: Set comprehesions, generalized unions and generalized intersections are quantified constructs. The predicate P must be a conjunction where the first n conjuncts must constraint the bounded variables. Restriction: Set comprehesions, generalized unions and generalized intersections are quantified constructs. The predicate P must be a conjunction where the first n conjuncts must constraint the bounded variables.
The i-th conjunct must constraint xi for each i in {1,...,n}. The i-th conjunct must constraint xi for each i in {1,...,n}.
...@@ -191,8 +191,8 @@ The i-th conjunct must constraint xi for each i in {1,...,n}. ...@@ -191,8 +191,8 @@ The i-th conjunct must constraint xi for each i in {1,...,n}.
| m / n | Division | | m / n | Division |
| m ** n | Power | | m ** n | Power |
| m mod n | Remainder of Division | | m mod n | Remainder of Division |
| PI(z1,...,zn).(P\|E) | Set product | | PI(z1,...,zn).(P &#124; E) | Set product |
| SIGMA(z1,...,zn).(P\|E) | Set summation | | SIGMA(z1,...,zn).(P &#124; E) | Set summation |
| succ(n) | Successor | | succ(n) | Successor |
| pred(n) | Predecessor | | pred(n) | Predecessor |
...@@ -206,22 +206,22 @@ The i-th conjunct must constraint xi for each i in {1,...,n}. ...@@ -206,22 +206,22 @@ The i-th conjunct must constraint xi for each i in {1,...,n}.
### Relations: ### Relations:
| Relation expression | Meaining | | Relation expression | Meaining |
|---------------------|-------------------------------------------------------| |----------------------|-------------------------------------------------------|
| S <-> T | Set of relation | | S <-> T | Set of relation |
| E \|-> F | Couple | | E &#124;-> F | Couple |
| dom(r) | Domain of Relation | | dom(r) | Domain of Relation |
| range(r) | Range of Relation | | range(r) | Range of Relation |
| id(S) | Identity Relation | | id(S) | Identity Relation |
| S <\| r | Domain Restriction | | S <&#124; r | Domain Restriction |
| S <<\| r | Domain Substraction | | S <<&#124; r | Domain Substraction |
| r \|> S | Range Restriction | | r &#124;> S | Range Restriction |
| r \|>> S | Range Substraction | | r &#124;>> S | Range Substraction |
| r~ | Inverse of Relation | | r~ | Inverse of Relation |
| r[S] | Relational Image | | r[S] | Relational Image |
| r1 <+ r2 | Relational Overriding | | r1 <+ r2 | Relational Overriding |
| r1 >< r2 | Direct Product | | r1 >< r2 | Direct Product |
| (r1 ; r2) | Relational Composition | | (r1 ; r2) | Relational Composition |
| (r1 \|\| r2) | Parallel Product | | (r1 &#124;&#124; r2) | Parallel Product |
| prj1(S,T) | Projection Function | | prj1(S,T) | Projection Function |
| prj2(S,T) | Projection Function | | prj2(S,T) | Projection Function |
| closure1(r) | Transitive Closure | | closure1(r) | Transitive Closure |
...@@ -267,8 +267,8 @@ The i-th conjunct must constraint xi for each i in {1,...,n}. ...@@ -267,8 +267,8 @@ The i-th conjunct must constraint xi for each i in {1,...,n}.
| front(S) | Front of Sequence | | front(S) | Front of Sequence |
| tail(S) | Tail of Sequence | | tail(S) | Tail of Sequence |
| conc(S) | Concatenation of Sequence of Sequences | | conc(S) | Concatenation of Sequence of Sequences |
| s /\|\ n | Take first n elements of sequence | | s /&#124;\ n | Take first n elements of sequence |
| s \\|/ n | Drop first n elements of sequence | | s \\&#124;/ n | Drop first n elements of sequence |
The following constructs are not supported for code generation: seq(S), seq1(S), iseq(S), iseq1(S) and perm(S). The following constructs are not supported for code generation: seq(S), seq1(S), iseq(S), iseq1(S) and perm(S).
They are only allowed in the predicate of constructs for verification such as invariant or precondition. They are only allowed in the predicate of constructs for verification such as invariant or precondition.
...@@ -313,7 +313,7 @@ Restriction: STRING is a infinite set. It is only supported on the right-hand si ...@@ -313,7 +313,7 @@ Restriction: STRING is a infinite set. It is only supported on the right-hand si
| x :: S | Choice from Set | | x :: S | Choice from Set |
| x : (P) | Choice by Predicate | | x : (P) | Choice by Predicate |
| x <-- OP(X) | Operation Call and Assignment of Return Value | | x <-- OP(X) | Operation Call and Assignment of Return Value |
| G \|\| H | Parallel Substitution | | G &#124;&#124; H | Parallel Substitution |
| G ; H | Sequential Substitution | | G ; H | Sequential Substitution |
| ANY x1,...,xn WHERE P THEN G END | Non Deterministic Choice | | ANY x1,...,xn WHERE P THEN G END | Non Deterministic Choice |
| LET x1,...,xn BE x1=E1 & ... & xn = En IN G END | Let Substitution | | LET x1,...,xn BE x1=E1 & ... & xn = En IN G END | Let Substitution |
......
...@@ -790,10 +790,6 @@ public class MachineGenerator implements AbstractVisitor<String, Void> { ...@@ -790,10 +790,6 @@ public class MachineGenerator implements AbstractVisitor<String, Void> {
return isIncludedMachine; return isIncludedMachine;
} }
public boolean isUseBigInteger() {
return useBigInteger;
}
public InvariantGenerator getInvariantGenerator() { public InvariantGenerator getInvariantGenerator() {
return invariantGenerator; return invariantGenerator;
} }
......
...@@ -5,7 +5,7 @@ return, short, signed, sizeof, static, static_cast, volatile, struct, switch, te ...@@ -5,7 +5,7 @@ return, short, signed, sizeof, static, static_cast, volatile, struct, switch, te
>> >>
machine(forModelChecking, imports, includedMachines, machine, structs, constants_declarations, includes, enums, sets, declarations, initialization, copyConstructor, operations, addition, useBigInteger, getters, transitions, invariant, copy, hash_equal, modelcheck, lambdaFunctions, mainMethod) ::= << machine(forModelChecking, imports, includedMachines, machine, structs, constants_declarations, includes, enums, sets, declarations, initialization, copyConstructor, operations, addition, useBigInteger, getters, transitions, invariant, copy, hash_equal, modelcheck, lambdaFunctions, mainMethod, transitionCachesDeclaration) ::= <<
#include \<iostream> #include \<iostream>
#include \<string> #include \<string>
<if(forModelChecking)> <if(forModelChecking)>
...@@ -20,6 +20,7 @@ machine(forModelChecking, imports, includedMachines, machine, structs, constants ...@@ -20,6 +20,7 @@ machine(forModelChecking, imports, includedMachines, machine, structs, constants
#include \<boost/asio/post.hpp> #include \<boost/asio/post.hpp>
#include \<boost/asio/thread_pool.hpp> #include \<boost/asio/thread_pool.hpp>
#include \<boost/any.hpp> #include \<boost/any.hpp>
#include \<boost/optional.hpp>
<endif> <endif>
<if(useBigInteger)> <if(useBigInteger)>
#include \<btypes_big_integer/BUtils.hpp> #include \<btypes_big_integer/BUtils.hpp>
...@@ -78,9 +79,16 @@ class <machine> { ...@@ -78,9 +79,16 @@ class <machine> {
<sets; separator="\n"> <sets; separator="\n">
<declarations; separator="\n"> <declarations; separator="\n">
<if(forModelChecking)>
<transitionCachesDeclaration; separator="\n">
<endif>
public: public:
<if(forModelChecking)>
std::string stateAccessedVia;
<endif>
<initialization> <initialization>
...@@ -484,19 +492,24 @@ if((<predicate>).booleanValue()) { ...@@ -484,19 +492,24 @@ if((<predicate>).booleanValue()) {
>> >>
transition(noParameters, noPredicate, identifier, subType, operationName, predicate, combination) ::= << transition(noParameters, noPredicate, identifier, subType, operationName, predicate, combination) ::= <<
<if(noParameters)>bool<else>BSet\<<subType>\><endif> _tr_<operationName>() const { <if(noParameters)>bool<else>BSet\<<subType>\><endif> _tr_<operationName>(bool isCaching) const {
if (this->_tr_cache_<operationName> == boost::none){
<if(noParameters)> <if(noParameters)>
<if(noPredicate)> <if(noPredicate)>
return true; return true;
<else> <else>
return (<predicate>).booleanValue(); this->_tr_cache_<operationName> = (<predicate>).booleanValue();
return this->_tr_cache_<operationName>.get();
<endif> <endif>
<else> <else>
BSet\<<subType>\> <identifier> = BSet\<<subType>\>(); BSet\<<subType>\> <identifier> = BSet\<<subType>\>();
<combination> <combination>
return <identifier>; if (isCaching) this->_tr_cache_<operationName> = <identifier>;
else return <identifier>;
<endif> <endif>
} }
return this->_tr_cache_<operationName>.get();
}
>> >>
invariant(invariantFunction, iterationConstruct, predicate) ::= << invariant(invariantFunction, iterationConstruct, predicate) ::= <<
...@@ -516,9 +529,25 @@ copy_assignment(variable) ::= << ...@@ -516,9 +529,25 @@ copy_assignment(variable) ::= <<
this-><variable> = <variable>; this-><variable> = <variable>;
>> >>
copy(machine, parameters) ::= << copy(machine, parameters, operations) ::= <<
<machine> _copy() const { static constexpr unsigned int strHash(const char *s, int off = 0) {
return <machine>(<parameters; separator=", ">); return !s[off] ? 5381 : (strHash(s, off+1)*33) ^ s[off];
}
<machine> _copy(unordered_set\<string> toInvalidate) const {
static const char* allTransitions[] = {<operations: {op | "_tr_<op>"}; separator=", ">};
<machine> result = <machine>(<parameters; separator=", ">);
for (const auto &item : allTransitions) {
if(toInvalidate.find(item) == toInvalidate.end()) {
switch(strHash(item)) {
<operations: {op | case strHash("_tr_<op>"): result._tr_cache_<op> = this->_tr_cache_<op>; break;}; separator="\n">
default: cout \<\< "Transition " \<\< item \<\< " not found!";
}
}
}
return result;
} }
>> >>
...@@ -993,11 +1022,7 @@ class ModelChecker { ...@@ -993,11 +1022,7 @@ class ModelChecker {
std::unordered_map\<string, std::unordered_set\<string>\> invariantDependency; std::unordered_map\<string, std::unordered_set\<string>\> invariantDependency;
std::unordered_map\<string, std::unordered_set\<string>\> guardDependency; std::unordered_map\<string, std::unordered_set\<string>\> guardDependency;
std::unordered_map\<<machine>, std::unordered_set\<string>, <machine>::Hash, <machine>::HashEqual> dependentInvariant;
std::unordered_map\<<machine>, std::unordered_set\<string>, <machine>::Hash, <machine>::HashEqual> dependentGuard;
std::unordered_map\<<machine>, immer::map\<string, boost::any>, <machine>::Hash, <machine>::HashEqual> guardCache;
std::unordered_map\<<machine>, <machine>, <machine>::Hash, <machine>::HashEqual> parents; std::unordered_map\<<machine>, <machine>, <machine>::Hash, <machine>::HashEqual> parents;
std::unordered_map\<<machine>, string, <machine>::Hash, <machine>::HashEqual> stateAccessedVia;
public: public:
ModelChecker() {} ModelChecker() {}
...@@ -1069,118 +1094,34 @@ model_check(addCachedInfos, nextStates, printResult, checkInvariants, main) ::= ...@@ -1069,118 +1094,34 @@ model_check(addCachedInfos, nextStates, printResult, checkInvariants, main) ::=
model_check_next_states(machine, transitionsWithCaching, transitionsWithoutCaching) ::= << model_check_next_states(machine, transitionsWithCaching, transitionsWithoutCaching) ::= <<
std::unordered_set\<<machine>, <machine>::Hash, <machine>::HashEqual> generateNextStates(const <machine>& state) { std::unordered_set\<<machine>, <machine>::Hash, <machine>::HashEqual> generateNextStates(const <machine>& state) {
std::unordered_set\<<machine>, <machine>::Hash, <machine>::HashEqual> result = std::unordered_set\<<machine>, <machine>::Hash, <machine>::HashEqual>(); std::unordered_set\<<machine>, <machine>::Hash, <machine>::HashEqual> result = std::unordered_set\<<machine>, <machine>::Hash, <machine>::HashEqual>();
if(isCaching) {
immer::map\<string, boost::any> parentsGuard;
immer::map\<string, boost::any> newCache;
bool parentsExist = (parents.find(state) != parents.end());
std::unordered_set\<string> dependentGuardsOfState;
bool dependentGuardsExist = false;
{
std::unique_lock\<std::mutex> lock(guardMutex);
dependentGuardsExist = (dependentGuard.find(state) != dependentGuard.end());
if(parentsExist) {
newCache = guardCache[parents[state]];
}
if((dependentGuardsExist)) {
dependentGuardsOfState = dependentGuard[state];
}
}
boost::any cachedValue;
bool dependentGuardsBoolean = true;
<transitionsWithCaching> <transitionsWithCaching>
{
std::unique_lock\<std::mutex> lock(guardMutex);
guardCache.insert({state, newCache});
}
} else {
<transitionsWithoutCaching>
}
return result; return result;
} }
>> >>
model_check_transition(hasParameters, tupleType, transitionIdentifier, evalTransitions, execTransitions, isCaching) ::= << model_check_transition(hasParameters, tupleType, transitionIdentifier, evalTransitions, execTransitions, isCaching) ::= <<
<if(hasParameters)> <if(hasParameters)>
<if(isCaching)> BSet\<<tupleType>\> <transitionIdentifier> = state.<evalTransitions>(isCaching);
BSet\<<tupleType>\> <transitionIdentifier>;
if(dependentGuardsExist) {
cachedValue = parentsGuard["<evalTransitions>"];
dependentGuardsBoolean = (dependentGuardsOfState.find("<evalTransitions>") != dependentGuardsOfState.end());
}
if(dependentGuardsExist || dependentGuardsBoolean || !parentsExist) {
<transitionIdentifier> = state.<evalTransitions>();
} else {
<transitionIdentifier> = boost::any_cast\<BSet\<<tupleType>\>>(cachedValue);
}
newCache = newCache.set("<evalTransitions>", <transitionIdentifier>);
for(const <tupleType>& param : <transitionIdentifier>) {
<execTransitions>
}
<else>
BSet\<<tupleType>\> <transitionIdentifier> = state.<evalTransitions>();
for(const <tupleType>& param : <transitionIdentifier>) { for(const <tupleType>& param : <transitionIdentifier>) {
<execTransitions> <execTransitions>
} }
<endif>
<else>
<if(isCaching)>
bool <transitionIdentifier>;
if(dependentGuardsExist) {
cachedValue = parentsGuard["<evalTransitions>"];
dependentGuardsBoolean = (dependentGuardsOfState.find("<evalTransitions>") != dependentGuardsOfState.end());
}
if(dependentGuardsExist || dependentGuardsBoolean || parentsExist) {
<transitionIdentifier> = state.<evalTransitions>();
} else {
<transitionIdentifier> = boost::any_cast\<bool>(cachedValue);
}
newCache = newCache.set("<evalTransitions>", <transitionIdentifier>);
if(<transitionIdentifier>) {
<execTransitions>
}
<else> <else>
if(state.<evalTransitions>()) { if(state.<evalTransitions>(isCaching)) {
<execTransitions> <execTransitions>
} }
<endif> <endif>
<endif>
>> >>
model_check_add_cached_infos(machine) ::= << model_check_add_cached_infos(machine) ::= <<
void addCachedInfos(const std::string& operation, const <machine>& state, const <machine>& copiedState) {
if(isCaching) {
std::unique_lock\<std::mutex> lock(guardMutex);
if(dependentInvariant.find(copiedState) == dependentInvariant.end()) {
dependentInvariant.insert({copiedState, invariantDependency[operation]});
}
if(dependentGuard.find(copiedState) == dependentGuard.end()) {
dependentGuard.insert({copiedState, guardDependency[operation]});
}
if(stateAccessedVia.find(copiedState) == stateAccessedVia.end()) {
stateAccessedVia.insert({copiedState, operation});
}
if(parents.find(copiedState) == parents.end()) {
parents.insert({copiedState, state});
}
} else {
std::unique_lock\<std::mutex> lock(guardMutex);
if(stateAccessedVia.find(copiedState) == stateAccessedVia.end()) {
stateAccessedVia.insert({copiedState, operation});
}
if(parents.find(copiedState) == parents.end()) {
parents.insert({copiedState, state});
}
}
}
>> >>
model_check_transition_body(machine, operation, hasParameters, readParameters, parameters, isCaching) ::= << model_check_transition_body(machine, operation, hasParameters, readParameters, parameters, isCaching) ::= <<
<if(hasParameters)> <if(hasParameters)>
<readParameters> <readParameters>
<endif> <endif>
<machine> copiedState = state._copy(); <machine> copiedState = state._copy(guardDependency["<operation>"]);
copiedState.<operation>(<parameters; separator=", ">); copiedState.<operation>(<parameters; separator=", ">);
addCachedInfos(std::string("<operation>"), state, copiedState); copiedState.stateAccessedVia = "<operation>";
result.insert(copiedState); result.insert(copiedState);
transitions += 1; transitions += 1;
>> >>
...@@ -1199,6 +1140,8 @@ model_check_transition_param_assignment(type, param, val, isLhs, oneParameter) : ...@@ -1199,6 +1140,8 @@ model_check_transition_param_assignment(type, param, val, isLhs, oneParameter) :
model_check_invariants(machine, invariantViolated) ::= << model_check_invariants(machine, invariantViolated) ::= <<
bool invariantViolated(const <machine>& state) { bool invariantViolated(const <machine>& state) {
std::unordered_set\<string> dependentInvariantsOfState;
if(isCaching) dependentInvariantsOfState = dependentInvariant[state];
<invariantViolated; separator="\n"> <invariantViolated; separator="\n">
return false; return false;
} }
...@@ -1206,7 +1149,6 @@ bool invariantViolated(const <machine>& state) { ...@@ -1206,7 +1149,6 @@ bool invariantViolated(const <machine>& state) {
model_check_invariant(invariant) ::= << model_check_invariant(invariant) ::= <<
if(isCaching) { if(isCaching) {
std::unordered_set\<string> dependentInvariantsOfState = dependentInvariant[state];
if(dependentInvariantsOfState.find("<invariant>") == dependentInvariantsOfState.end()) { if(dependentInvariantsOfState.find("<invariant>") == dependentInvariantsOfState.end()) {
if(!state.<invariant>()) { if(!state.<invariant>()) {
cout \<\< "INVARIANT CONJUNCT VIOLATED: <invariant>" \<\< "\n"; cout \<\< "INVARIANT CONJUNCT VIOLATED: <invariant>" \<\< "\n";
...@@ -1245,7 +1187,7 @@ void printResult() { ...@@ -1245,7 +1187,7 @@ void printResult() {
stringStream \<\< counterExampleState; stringStream \<\< counterExampleState;
trace.insert(0, stringStream.str()); trace.insert(0, stringStream.str());
trace.insert(0, "\n"); trace.insert(0, "\n");
trace.insert(0, stateAccessedVia[counterExampleState]); trace.insert(0, counterExampleState.stateAccessedVia);
trace.insert(0, "\n\n"); trace.insert(0, "\n\n");
counterExampleState = parents[counterExampleState]; counterExampleState = parents[counterExampleState];
} }
...@@ -1294,6 +1236,7 @@ void modelCheckSingleThreaded() { ...@@ -1294,6 +1236,7 @@ void modelCheckSingleThreaded() {
for(auto& nextState : nextStates) { for(auto& nextState : nextStates) {
if(states.find(nextState) == states.end()) { if(states.find(nextState) == states.end()) {
states.insert(nextState); states.insert(nextState);
parents.insert({nextState, state});
unvisitedStates.push_back(nextState); unvisitedStates.push_back(nextState);
if(states.size() % 50000 == 0) { if(states.size() % 50000 == 0) {
cout \<\< "VISITED STATES: " \<\< states.size() \<\< "\n"; cout \<\< "VISITED STATES: " \<\< states.size() \<\< "\n";
...@@ -1347,6 +1290,7 @@ void modelCheckMultiThreaded(boost::asio::thread_pool& workers) { ...@@ -1347,6 +1290,7 @@ void modelCheckMultiThreaded(boost::asio::thread_pool& workers) {
std::unique_lock\<std::mutex> lock(mutex); std::unique_lock\<std::mutex> lock(mutex);
if(states.find(nextState) == states.end()) { if(states.find(nextState) == states.end()) {
states.insert(nextState); states.insert(nextState);
parents.insert({nextState, state});
unvisitedStates.push_back(nextState); // TODO: sync ? unvisitedStates.push_back(nextState); // TODO: sync ?
if(isDebug && states.size() % 50000 == 0) { if(isDebug && states.size() % 50000 == 0) {
cout \<\< "VISITED STATES: " \<\< states.size() \<\< "\n"; cout \<\< "VISITED STATES: " \<\< states.size() \<\< "\n";
...@@ -1389,7 +1333,7 @@ void modelCheckMultiThreaded(boost::asio::thread_pool& workers) { ...@@ -1389,7 +1333,7 @@ void modelCheckMultiThreaded(boost::asio::thread_pool& workers) {
{ {
std::unique_lock\<std::mutex> lock(waitMutex); std::unique_lock\<std::mutex> lock(waitMutex);
if (unvisitedStates.empty() && possibleQueueChanges > 0) { while (unvisitedStates.empty() && possibleQueueChanges > 0) {
waitCV.wait(lock, [&] { waitCV.wait(lock, [&] {
return waitFlag == false; return waitFlag == false;
}); });
...@@ -1402,8 +1346,8 @@ void modelCheckMultiThreaded(boost::asio::thread_pool& workers) { ...@@ -1402,8 +1346,8 @@ void modelCheckMultiThreaded(boost::asio::thread_pool& workers) {
void initCache(<machine>& machine) { void initCache(<machine>& machine) {
<invariantDependency; separator="\n"> <invariantDependency; separator="\n">
invariantDependency.insert({"", {}});
<guardDependency; separator="\n"> <guardDependency; separator="\n">
dependentInvariant.insert({machine, std::unordered_set\<string>()});
} }
>> >>
...@@ -1472,4 +1416,5 @@ include_initialization() ::= << ...@@ -1472,4 +1416,5 @@ include_initialization() ::= <<
>> >>
transition_cache_declaration(type, identifier, operationHasParams) ::= << transition_cache_declaration(type, identifier, operationHasParams) ::= <<
mutable boost::optional\<<if(operationHasParams)>BSet\<<type>\><else>bool<endif>\> _tr_cache_<identifier>;
>> >>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment