void computeAndPrintExplicitStateStrategy(std::ostream &outputStream) { // We don't want any reordering from this point onwards, as // the BDD manipulations from this point onwards are 'kind of simple'. mgr.setAutomaticOptimisation(false); // List of states in existance so far. The first map // maps from a BF node pointer (for the pre variable valuation) and a goal // to a state number. The vector then contains the concrete valuation. std::map<std::pair<size_t, std::pair<unsigned int, unsigned int> >, unsigned int > lookupTableForPastStates; std::vector<BF> bfsUsedInTheLookupTable; std::list<std::pair<size_t, std::pair<unsigned int, unsigned int> > > todoList; // Prepare positional strategies for the individual goals std::vector<std::vector<BF> > positionalStrategiesForTheIndividualGoals(livenessAssumptions.size()); for (unsigned int i=0;i<livenessAssumptions.size();i++) { //BF casesCovered = mgr.constantFalse(); std::vector<BF> strategy(livenessGuarantees.size()+1); for (unsigned int j=0;j<livenessGuarantees.size()+1;j++) { strategy[j] = mgr.constantFalse(); } for (auto it = strategyDumpingData.begin();it!=strategyDumpingData.end();it++) { if (boost::get<0>(*it) == i) { //Have to cover each guarantee (since the winning strategy depends on which guarantee is being pursued) //Essentially, the choice of which guarantee to pursue can be thought of as a system "move". //The environment always to chooses that prevent the appropriate guarantee. strategy[boost::get<1>(*it)] |= boost::get<2>(*it).UnivAbstract(varCubePostOutput) & !(strategy[boost::get<1>(*it)].ExistAbstract(varCubePost)); } } positionalStrategiesForTheIndividualGoals[i] = strategy; } // Prepare initial to-do list from the allowed initial states. Select a single initial input valuation. // TODO: Support for non-special-robotics semantics BF todoInit = (winningPositions & initEnv & initSys); while (!(todoInit.isFalse())) { BF concreteState = determinize(todoInit,preVars); //find which liveness guarantee is being prevented (finds the first liveness in order specified) // Note by Ruediger here: Removed "!livenessGuarantees[j]" as condition as it is non-positional unsigned int found_j_index = 0; for (unsigned int j=0;j<livenessGuarantees.size();j++) { if (!(concreteState & positionalStrategiesForTheIndividualGoals[0][j]).isFalse()) { found_j_index = j; break; } } std::pair<size_t, std::pair<unsigned int, unsigned int> > lookup = std::pair<size_t, std::pair<unsigned int, unsigned int> >(concreteState.getHashCode(),std::pair<unsigned int, unsigned int>(0,found_j_index)); lookupTableForPastStates[lookup] = bfsUsedInTheLookupTable.size(); bfsUsedInTheLookupTable.push_back(concreteState); //from now on use the same initial input valuation (but consider all other initial output valuations) todoInit &= !concreteState; todoList.push_back(lookup); } // Extract strategy while (todoList.size()>0) { std::pair<size_t, std::pair<unsigned int, unsigned int> > current = todoList.front(); todoList.pop_front(); unsigned int stateNum = lookupTableForPastStates[current]; BF currentPossibilities = bfsUsedInTheLookupTable[stateNum]; // Print state information outputStream << "State " << stateNum << " with rank (" << current.second.first << "," << current.second.second << ") -> <"; bool first = true; for (unsigned int i=0;i<variables.size();i++) { if (doesVariableInheritType(i,Pre)) { if (first) { first = false; } else { outputStream << ", "; } outputStream << variableNames[i] << ":"; outputStream << (((currentPossibilities & variables[i]).isFalse())?"0":"1"); } } outputStream << ">\n\tWith successors : "; first = true; // Can we enforce a deadlock? BF deadlockInput = (currentPossibilities & safetyEnv & !safetySys).UnivAbstract(varCubePostOutput); if (deadlockInput!=mgr.constantFalse()) { addDeadlocked(deadlockInput, current, bfsUsedInTheLookupTable, lookupTableForPastStates, outputStream); } else { // No deadlock in sight -> Jump to a different liveness guarantee if necessary. while ((currentPossibilities & positionalStrategiesForTheIndividualGoals[current.second.first][current.second.second])==mgr.constantFalse()) current.second.second = (current.second.second + 1) % livenessGuarantees.size(); currentPossibilities &= positionalStrategiesForTheIndividualGoals[current.second.first][current.second.second]; assert(currentPossibilities != mgr.constantFalse()); BF remainingTransitions = currentPossibilities; // save any combination of pre variables and post inputs found that are not included in player 1's strategy BF_newDumpDot(*this,remainingTransitions,NULL,"/tmp/remainingTransitions.dot"); BF foundCutConditions = (!remainingTransitions.ExistAbstract(varCubePre)) & remainingTransitions.ExistAbstract(varCubePost); candidateFailingPreConditions |= remainingTransitions; BF_newDumpDot(*this,!(remainingTransitions).ExistAbstract(varCubePre),NULL,"/tmp/candidateWinningThisState.dot"); std::stringstream ss1; std::stringstream ss2; ss1 << "/tmp/candidateWinning" << stateNum << ".dot"; ss2 << "/tmp/remainingTransitions" << stateNum << ".dot"; BF_newDumpDot(*this,(!remainingTransitions.ExistAbstract(varCubePre)) & remainingTransitions.ExistAbstract(varCubePost),NULL,ss1.str()); BF_newDumpDot(*this,remainingTransitions,NULL,ss2.str()); // Choose one next input and stick to it! // BF_newDumpDot(*this,remainingTransitions,NULL,"/tmp/remainingTransitionsBefore.dot"); remainingTransitions = determinize(remainingTransitions,postInputVars); // BF_newDumpDot(*this,remainingTransitions,NULL,"/tmp/remainingTransitionsAfter.dot"); // Switching goals while (!(remainingTransitions & safetySys).isFalse()) { BF safeTransition = remainingTransitions & safetySys; BF newCombination = determinize(safeTransition, postOutputVars); foundCutPostConditions |= foundCutConditions & newCombination.ExistAbstract(varCubePre).ExistAbstract(varCubePostInput); // Jump as much forward in the liveness assumption list as possible ("stuttering avoidance") unsigned int nextLivenessAssumption = current.second.first; bool firstTry = true; while (((nextLivenessAssumption != current.second.first) | firstTry) && !((livenessAssumptions[nextLivenessAssumption] & newCombination).isFalse())) { nextLivenessAssumption = (nextLivenessAssumption + 1) % livenessAssumptions.size(); firstTry = false; } //Mark which input has been captured by this case. Use the same input for other successors remainingTransitions &= !newCombination; // We don't need the pre information from the point onwards anymore. newCombination = newCombination.ExistAbstract(varCubePre).SwapVariables(varVectorPre,varVectorPost); unsigned int tn; std::pair<size_t, std::pair<unsigned int, unsigned int> > target; target = std::pair<size_t, std::pair<unsigned int, unsigned int> >(newCombination.getHashCode(),std::pair<unsigned int, unsigned int>(nextLivenessAssumption, current.second.second)); if (lookupTableForPastStates.count(target)==0) { tn = lookupTableForPastStates[target] = bfsUsedInTheLookupTable.size(); bfsUsedInTheLookupTable.push_back(newCombination); todoList.push_back(target); } else { tn = lookupTableForPastStates[target]; } // Print if (first) { first = false; } else { outputStream << ", "; } outputStream << tn; } } outputStream << "\n"; } }
/** * @brief Compute and print out (to stdout) an explicit-state strategy that is winning for * the system. The output is compatible with the old JTLV output of LTLMoP. * This function requires that the realizability of the specification has already been * detected and that the variables "strategyDumpingData" and * "winningPositions" have been filled by the synthesis algorithm with meaningful data. * @param outputStream - Where the strategy shall be printed to. */ void computeAndPrintExplicitStateStrategy(std::ostream &outputStream) { // We don't want any reordering from this point onwards, as // the BDD manipulations from this point onwards are 'kind of simple'. mgr.setAutomaticOptimisation(false); // List of states in existance so far. The first map // maps from a BF node pointer (for the pre variable valuation) and a goal // to a state number. The vector then contains the concrete valuation. std::map<std::pair<size_t, unsigned int>, unsigned int > lookupTableForPastStates; std::vector<BF> bfsUsedInTheLookupTable; std::list<std::pair<size_t, unsigned int> > todoList; // Prepare initial to-do list from the allowed initial states BF todoInit = (oneStepRecovery)?(winningPositions & initSys):(winningPositions & initSys & initEnv); while (!(todoInit.isFalse())) { BF concreteState = determinize(todoInit,preVars); std::pair<size_t, unsigned int> lookup = std::pair<size_t, unsigned int>(concreteState.getHashCode(),0); lookupTableForPastStates[lookup] = bfsUsedInTheLookupTable.size(); bfsUsedInTheLookupTable.push_back(concreteState); todoInit &= !concreteState; todoList.push_back(lookup); } // Prepare positional strategies for the individual goals std::vector<BF> positionalStrategiesForTheIndividualGoals(livenessGuarantees.size()); for (unsigned int i=0;i<livenessGuarantees.size();i++) { BF casesCovered = mgr.constantFalse(); BF strategy = mgr.constantFalse(); for (auto it = strategyDumpingData.begin();it!=strategyDumpingData.end();it++) { if (it->first == i) { BF newCases = it->second.ExistAbstract(varCubePostOutput) & !casesCovered; strategy |= newCases & it->second; casesCovered |= newCases; } } positionalStrategiesForTheIndividualGoals[i] = strategy; //BF_newDumpDot(*this,strategy,"PreInput PreOutput PostInput PostOutput","/tmp/generalStrategy.dot"); } // Extract strategy while (todoList.size()>0) { std::pair<size_t, unsigned int> current = todoList.front(); todoList.pop_front(); unsigned int stateNum = lookupTableForPastStates[current]; BF currentPossibilities = bfsUsedInTheLookupTable[stateNum]; /*{ std::ostringstream filename; filename << "/tmp/state" << stateNum << ".dot"; BF_newDumpDot(*this,currentPossibilities,"PreInput PreOutput PostInput PostOutput",filename.str()); }*/ // Print state information outputStream << "State " << stateNum << " with rank " << current.second << " -> <"; bool first = true; for (unsigned int i=0;i<variables.size();i++) { if (variableTypes[i] < PostInput) { if (first) { first = false; } else { outputStream << ", "; } outputStream << variableNames[i] << ":"; outputStream << (((currentPossibilities & variables[i]).isFalse())?"0":"1"); } } outputStream << ">\n\tWith successors : "; first = true; // Compute successors for all variables that allow these currentPossibilities &= positionalStrategiesForTheIndividualGoals[current.second]; BF remainingTransitions = (oneStepRecovery)? currentPossibilities: (currentPossibilities & safetyEnv); // Switching goals while (!(remainingTransitions.isFalse())) { BF newCombination = determinize(remainingTransitions,postVars); // Jump as much forward in the liveness guarantee list as possible ("stuttering avoidance") unsigned int nextLivenessGuarantee = current.second; bool firstTry = true; while (((nextLivenessGuarantee != current.second) || firstTry) && !((livenessGuarantees[nextLivenessGuarantee] & newCombination).isFalse())) { nextLivenessGuarantee = (nextLivenessGuarantee + 1) % livenessGuarantees.size(); firstTry = false; } // Mark which input has been captured by this case BF inputCaptured = newCombination.ExistAbstract(varCubePostOutput); newCombination = newCombination.ExistAbstract(varCubePre).SwapVariables(varVectorPre,varVectorPost); remainingTransitions &= !inputCaptured; // Search for newCombination unsigned int tn; std::pair<size_t, unsigned int> target = std::pair<size_t, unsigned int>(newCombination.getHashCode(),nextLivenessGuarantee); if (lookupTableForPastStates.count(target)==0) { tn = lookupTableForPastStates[target] = bfsUsedInTheLookupTable.size(); bfsUsedInTheLookupTable.push_back(newCombination); todoList.push_back(target); } else { tn = lookupTableForPastStates[target]; } // Print if (first) { first = false; } else { outputStream << ", "; } outputStream << tn; } outputStream << "\n"; } }
void addDeadlocked(BF targetPositionCandidateSet, std::pair<size_t, std::pair<unsigned int, unsigned int> > current, std::vector<BF> &bfsUsedInTheLookupTable, std::map<std::pair<size_t, std::pair<unsigned int, unsigned int> >, unsigned int > &lookupTableForPastStates, std::ostream &outputStream) { BF newCombination = determinize(targetPositionCandidateSet, postVars) ; newCombination = newCombination.ExistAbstract(varCubePreOutput).SwapVariables(varVectorPre,varVectorPost); std::pair<size_t, std::pair<unsigned int, unsigned int> > target = std::pair<size_t, std::pair<unsigned int, unsigned int> >(newCombination.getHashCode(),std::pair<unsigned int, unsigned int>(current.second.first, current.second.second)); unsigned int tn; if (lookupTableForPastStates.count(target)==0) { tn = lookupTableForPastStates[target] = bfsUsedInTheLookupTable.size(); bfsUsedInTheLookupTable.push_back(newCombination); outputStream << tn << "\n"; //Note that since we are printing here, we usually end up with the states being printed out of order. //TOTO: print in order outputStream << "State " << tn << " with rank (" << current.second.first << "," << current.second.second << ") -> <"; bool first = true; for (unsigned int i=0;i<variables.size();i++) { if (doesVariableInheritType(i,PreInput)) { if (first) { first = false; } else { outputStream << ", "; } outputStream << variableNames[i] << ":"; outputStream << (((newCombination & variables[i]).isFalse())?"0":"1"); } } outputStream << ">\n\tWith no successors."; } else { tn = lookupTableForPastStates[target]; outputStream << tn; } }