void addAutomaticallyGeneratedSafeties() {
        
        // Create new safety assumptions describing which regions the robot can end up in given the currently active controllers 
        // and new safety guarantees describing which controllers can be activated

        BF newSafetyEnv = robotBDD;
        BF newSafetySys = robotBDD.ExistAbstract(varCubePostMotionState);
        
        safetyEnv &= newSafetyEnv;
        safetySys &= newSafetySys;
        std::cerr << "Note: Added a safety assumption and guarantee describing the robot's allowed transitions.\n";
        BF_newDumpDot(*this,newSafetyEnv,"PreMotionState PreMotionControlOutput PostMotionState","/tmp/changeMotionStateSafetyAssumption.dot");

    }
    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;
    }
    
}
    /**
     * @brief Modified basic synthesis algorithm - adds to 'strategyDumpingData' transitions
     * that represent "a bias for action"
     */
    void computeWinningPositions() {

        // Compute system transitions that are not environment dead-ends.
        // The system is only allowed to use these.
        BF nonDeadEndSafetySys = safetySys & safetyEnv.ExistAbstract(varCubePost).SwapVariables(varVectorPre,varVectorPost);
        // BF_newDumpDot(*this,nonDeadEndSafetySys,"Pre Post","/tmp/nonDeadEndSys.dot");
        // BF_newDumpDot(*this,safetyEnv.ExistAbstract(varCubePost).SwapVariables(varVectorPre,varVectorPost),"Pre Post","/tmp/notDeadEndSafetyEnv.dot");

        // Copy all liveness assumptions into liveness guarantees - we are
        // them seperately at the end of a "guarantee cycle".
        for (auto it = livenessAssumptions.begin();it!=livenessAssumptions.end();it++) {
            livenessGuarantees.push_back(*it);
        }
        std::vector<BF> transitionsTowardsLivenessAssumption(livenessAssumptions.size());

        // The greatest fixed point - called "Z" in the GR(1) synthesis paper
        BFFixedPoint nu2(mgr.constantTrue());
        unsigned int nu2Nr = 0;

        // Iterate until we have found a fixed point
        for (;!nu2.isFixedPointReached();) {
            nu2Nr++;

            // To extract a strategy in case of realizability, we need to store a sequence of 'preferred' transitions in the
            // game structure. These preferred transitions only need to be computed during the last execution of the outermost
            // greatest fixed point. Since we don't know which one is the last one, we store them in every iteration,
            // so that after the last iteration, we obtained the necessary data. Before any new iteration, we need to
            // clear the old data, though.
            strategyDumpingData.clear();

            // Iterate over all of the liveness guarantees. Put the results into the variable 'nextContraintsForGoals' for every
            // goal. Then, after we have iterated over the goals, we can update nu2.
            BF nextContraintsForGoals = mgr.constantTrue();
            for (unsigned int j=0;j<livenessGuarantees.size()-livenessAssumptions.size();j++) {

                // Start computing the transitions that lead closer to the goal and lead to a position that is not yet known to be losing.
                // Start with the ones that actually represent reaching the goal (which is a transition in this implementation as we can have
                // nexts in the goal descriptions).
                BF livetransitions = livenessGuarantees[j] & (nu2.getValue().SwapVariables(varVectorPre,varVectorPost));

                // Compute the middle least-fixed point (called 'Y' in the GR(1) paper)
                BFFixedPoint mu1(mgr.constantFalse());
                unsigned int mu1Nr = 0;
                for (;!mu1.isFixedPointReached();) {
                    mu1Nr++;

                    // Update the set of transitions that lead closer to the goal.
                    livetransitions |= mu1.getValue().SwapVariables(varVectorPre,varVectorPost);

                    // { std::ostringstream os;
                    // os << "/tmp/livetransitions" << nu2Nr << "-" << j << "-" << mu1Nr << ".dot";
                    // BF_newDumpDot(*this,livetransitions,"Pre Post",os.str()); }

                    // Iterate over the liveness assumptions. Store the positions that are found to be winning for *any*
                    // of them into the variable 'goodForAnyLivenessAssumption'.
                    BF goodForAnyLivenessAssumption = mu1.getValue();
                    for (unsigned int i=0;i<livenessAssumptions.size();i++) {

                        // Prepare the variable 'foundPaths' that contains the transitions that stay within the inner-most
                        // greatest fixed point or get closer to the goal. Only used for strategy extraction
                        BF foundPaths = mgr.constantTrue();

                        // Allocate space for storing the transitions that allow the satisfaction of
                        // the liveness assumptions
                        std::vector<BF> livenessAssumptionProgressPaths;

                        // Inner-most greatest fixed point. The corresponding variable in the paper would be 'X'.
                        BFFixedPoint nu0(mgr.constantTrue());
                        unsigned int nu0Nr = 0;
                        for (;!nu0.isFixedPointReached();) {

                            nu0Nr++;

                            // Cooperation: Compute set of states from which a live transition can be
                            // reached (somehow)
                            BFFixedPoint muCoop(mgr.constantFalse());
                            unsigned int muCoopNr = 0;
                            livenessAssumptionProgressPaths.clear();
                            livenessAssumptionProgressPaths.push_back(livetransitions);
                            for (;!muCoop.isFixedPointReached();) {
                                muCoopNr++;
                                foundPaths = livetransitions | ((nu0.getValue() & muCoop.getValue()).SwapVariables(varVectorPre,varVectorPost) & !(livenessAssumptions[i]));
                                foundPaths &= nonDeadEndSafetySys & safetyEnv;

                                // { std::ostringstream os;
                                // os << "/tmp/foundPaths" << nu2Nr << "-" << j << "-" << mu1Nr << "-" << i << "-" << nu0Nr << "--" << muCoopNr << ".dot";
                                // BF_newDumpDot(*this,foundPaths,"Pre Post",os.str()); }

                                livenessAssumptionProgressPaths.push_back(foundPaths);
                                muCoop.update((safetyEnv & foundPaths).ExistAbstract(varCubePost));

                                // { std::ostringstream os;
                                // os << "/tmp/muCoop" << nu2Nr << "-" << j << "-" << mu1Nr << "-" << i << "-" << nu0Nr << "--" << muCoopNr << ".dot";
                                // BF_newDumpDot(*this,muCoop.getValue(),"Pre Post",os.str()); }
                            }

                            // { std::ostringstream os;
                            // os << "/tmp/foundPathsFinal" << nu2Nr << "-" << j << "-" << mu1Nr << "-" << i << ".dot";
                            // BF_newDumpDot(*this,foundPaths,"Pre Post",os.str()); }


                            // Update the inner-most fixed point with the result of applying the enforcable predecessor operator
                            nu0.update(safetyEnv.Implies(foundPaths).ExistAbstract(varCubePostOutput).UnivAbstract(varCubePostInput));

                            // { std::ostringstream os;
                            // os << "/tmp/nu0-" << nu2Nr << "-" << j << "-" << mu1Nr << "-" << i << "-" << nu0Nr << ".dot";
                            // BF_newDumpDot(*this,nu0.getValue(),"Pre Post",os.str()); }

                        }

                        // Update the set of positions that are winning for some liveness assumption
                        goodForAnyLivenessAssumption |= nu0.getValue();

                        // Dump the paths that we just wound into 'strategyDumpingData' - store the current goal long
                        // with the BDD
                        for (auto it = livenessAssumptionProgressPaths.begin();it!=livenessAssumptionProgressPaths.end();it++) {
                            strategyDumpingData.push_back(std::pair<unsigned int,BF>(j,foundPaths & *it));
                        }
                    }

                    // Update the moddle fixed point
                    mu1.update(goodForAnyLivenessAssumption);

                    // { std::ostringstream os;
                    // os << "/tmp/mu1-" << nu2Nr << "-" << j << "-" << mu1Nr << ".dot";
                    // BF_newDumpDot(*this,mu1.getValue(),"Pre Post",os.str()); }
                }

                // Update the set of positions that are winning for any goal for the outermost fixed point
                nextContraintsForGoals &= mu1.getValue();
            }

            // Now iterate over the liveness assumptions
            // and compute a sub-strategy to ensure that there is always some way in which the
            // liveness assumptions can be satisfied
            for (unsigned int j=livenessGuarantees.size()-livenessAssumptions.size();j<livenessGuarantees.size();j++) {

                BF currentLivenessAssumption = livenessGuarantees[j];

                // Collect a set of paths to satisfy this liveness assumption, while the system can
                // always enforce to land in a winning state afterwards
                BFFixedPoint mu1(mgr.constantFalse());
                unsigned int mu1Nr = 0;
                BF goodTransitions = currentLivenessAssumption & nonDeadEndSafetySys & nextContraintsForGoals & safetyEnv & nextContraintsForGoals.SwapVariables(varVectorPre,varVectorPost);

                for (;!mu1.isFixedPointReached();) {
                    mu1Nr++;

                    // { std::ostringstream os;
                    // os << "/tmp/fairtransitions-" << nu2Nr << "-" << j << "-" << mu1Nr << ".dot";
                    // BF_newDumpDot(*this,goodTransitions,"Pre Post",os.str()); }

                    // { std::ostringstream os;
                    // os << "/tmp/fairtransitionCL-" << nu2Nr << "-" << j << "-" << mu1Nr << ".dot";
                    // BF_newDumpDot(*this,currentLivenessAssumption,"Pre Post",os.str()); }

                    // { std::ostringstream os;
                    // os << "/tmp/fairmu-" << nu2Nr << "-" << j << "-" << mu1Nr << ".dot";
                    // BF_newDumpDot(*this,mu1.getValue(),"Pre Post",os.str()); }


                    // Dump good transitions
                    strategyDumpingData.push_back(std::pair<unsigned int,BF>(j,goodTransitions));

                    // From which states can we enforce that the environment can enforce a
                    // goodTransition? We cannot offer losing transitions.

                    BF winningStates = goodTransitions.ExistAbstract(varCubePost);
                    goodTransitions |= winningStates.SwapVariables(varVectorPre,varVectorPost) & safetyEnv & nonDeadEndSafetySys & nextContraintsForGoals;
                    mu1.update(winningStates | mu1.getValue());
                }
                nextContraintsForGoals &= mu1.getValue();
                transitionsTowardsLivenessAssumption[j-(livenessGuarantees.size()-livenessAssumptions.size())] = goodTransitions;

                // Backup transitions not towards the goal
                strategyDumpingData.push_back(std::pair<unsigned int,BF>(j,nonDeadEndSafetySys & nu2.getValue().SwapVariables(varVectorPre,varVectorPost)));
            }


            // Update the outer-most fixed point
            nu2.update(nextContraintsForGoals);

            // { std::ostringstream os;
            // os << "/tmp/nu2-" << nu2Nr << ".dot";
            // BF_newDumpDot(*this,nu2.getValue(),"Pre Post",os.str()); }
        }

        // Modify the additional liveness guarantees to be satisfied once the environment deviated
        // from the paths towards the environment liveness goal.
        for (unsigned int j=livenessGuarantees.size()-livenessAssumptions.size();j<livenessGuarantees.size();j++) {
            livenessGuarantees[j] |= !transitionsTowardsLivenessAssumption[j-(livenessGuarantees.size()-livenessAssumptions.size())];
        }

        // We found the set of winning positions
        winningPositions = nu2.getValue();

    }
    /**
     * @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 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";
    }
    }
 void computeWinningPositions() {

    // The greatest fixed point - called "Z" in the GR(1) synthesis paper
    BFFixedPoint mu2(mgr.constantFalse());

    // Iterate until we have found a fixed point
    for (;!mu2.isFixedPointReached();) {

        // Iterate over all of the liveness guarantees. Put the results into the variable 'nextContraintsForGoals' for every
        // goal. Then, after we have iterated over the goals, we can update mu2.
        BF nextContraintsForGoals = mgr.constantFalse();
        for (unsigned int j=0;j<livenessGuarantees.size();j++) {

            // To extract a counterstrategy in case of unrealizability, we need to store a sequence of 'preferred' transitions in the
            // game structure. These preferred transitions only need to be computed during the last execution of the middle
            // greatest fixed point. Since we don't know which one is the last one, we store them in every iteration,
            // so that after the last iteration, we obtained the necessary data. Before any new iteration, we need to
            // store the old date so that it can be discarded if needed
            std::vector<boost::tuple<unsigned int, unsigned int,BF> > strategyDumpingDataOld = strategyDumpingData;

            // Start computing the transitions that lead closer to the goal and lead to a position that is not yet known to be losing (for the environment).
            // Start with the ones that actually represent reaching the goal (which is a transition in this implementation as we can have
            // nexts in the goal descriptions).
            BF livetransitions = (!livenessGuarantees[j]) | (mu2.getValue().SwapVariables(varVectorPre,varVectorPost));

            // Compute the middle least-fixed point (called 'Y' in the GR(1) paper)
            BFFixedPoint nu1(mgr.constantTrue());
            for (;!nu1.isFixedPointReached();) {

                // New middle iteration has begun -> revert to the data before the first iteration.
                strategyDumpingData = strategyDumpingDataOld;

                // Update the set of transitions that lead closer to the goal.
                livetransitions &= nu1.getValue().SwapVariables(varVectorPre,varVectorPost);

                // Iterate over the liveness assumptions. Store the positions that are found to be winning for *all*
                // of them into the variable 'goodForAnyLivenessAssumption'.
                BF goodForAllLivenessAssumptions = nu1.getValue();
                for (unsigned int i=0;i<livenessAssumptions.size();i++) {

                    // Prepare the variable 'foundPaths' that contains the transitions that stay within the inner-most
                    // greatest fixed point or get closer to the goal. Only used for counterstrategy extraction
                    BF foundPaths = mgr.constantFalse();

                    // Inner-most greatest fixed point. The corresponding variable in the paper would be 'X'.
                    BFFixedPoint mu0(mgr.constantFalse());
                    for (;!mu0.isFixedPointReached();) {

                        // Compute a set of paths that are safe to take - used for the enforceable predecessor operator ('cox')
                        foundPaths = livetransitions & (mu0.getValue().SwapVariables(varVectorPre,varVectorPost) | (livenessAssumptions[i]));
                        foundPaths = (safetyEnv & safetySys.Implies(foundPaths)).UnivAbstract(varCubePostOutput);

                        // Dump the paths that we just found into 'strategyDumpingData' - store the current goal
                        // with the BDD
                        strategyDumpingData.push_back(boost::make_tuple(i,j,foundPaths));

                        // Update the inner-most fixed point with the result of applying the enforcable predecessor operator
                        mu0.update(foundPaths.ExistAbstract(varCubePostInput));
                    }

                    // Update the set of positions that are winning for some liveness assumption
                    goodForAllLivenessAssumptions &= mu0.getValue();

                }

                // Update the middle fixed point
                nu1.update(goodForAllLivenessAssumptions);
            }

            // Update the set of positions that are winning for some environment goal for the outermost fixed point
            nextContraintsForGoals |= nu1.getValue();
        }

        // Update the outer-most fixed point
        mu2.update(nextContraintsForGoals);

    }

    // We found the set of winning positions
    winningPositions = mu2.getValue();
}
Exemple #7
0
/**
 * Internal function for BDD dumping
 */
std::pair<int,unsigned int> BDD_newDumpDotRecurse(const BF &bdd, int level, RecurseContext &rc) {
	
        const BFManager *cudd = bdd.manager();
	if (rc.nodesSoFar>MAX_NODES_GRAPH) return std::pair<int,unsigned int>(-1,0);
	
	// Constant nodes?
    if (bdd==cudd->constantFalse()) return std::pair<int,unsigned int>(-1,0);
    if (bdd==cudd->constantTrue()) return std::pair<int,unsigned int>(-1,1);
	
	// int index = bdd.NodeReadIndex();
	if (level==(int)(rc.vars.size())) {
		#ifdef USE_BDD
		int index = bdd.readNodeIndex();
		std::ostringstream errorMsg;
		errorMsg << "MyDumpDot: Variable List was incomplete. Variable missing (" << index << "): " << rc.io.getVariableName(index);
                std::cerr << errorMsg.str() << std::endl;
		throw BFDumpDotException(errorMsg.str());
		#else
		throw BFDumpDotException("MyDumpDot: Variable List was incomplete. Variable missing (unknown);");
		#endif
	}
	
	// While not dependent on this var skip to next one
	BF currentVar;
	BF zeroBranch;
	BF oneBranch;
	bool depends = false;
	
	while ((!depends) && (level<(int)(rc.vars.size()))) {
		currentVar = rc.io.getVariableBF(rc.vars[level]);
		
		BF cube[1];
		int phase[1];
		phase[0] = 1;
		cube[0] = currentVar;
		
		zeroBranch = bdd & (!currentVar);
		zeroBranch = zeroBranch.ExistAbstract( cudd->computeCube(cube,phase,1));
		oneBranch = bdd & (currentVar);
		oneBranch = oneBranch.ExistAbstract( cudd->computeCube(cube,phase,1));
				
		if (oneBranch==zeroBranch) {
			level++;
		} else {
			depends = true;
		}
		
	}
		
	if (level==(int)(rc.vars.size())) {
		#ifdef USE_BDD
		int index = bdd.readNodeIndex();
		std::ostringstream errorMsg;
		errorMsg << "MyDumpDot: Variable List was incomplete. Variable missing (" << index << "): " << rc.io.getVariableName(index);
                std::cerr << errorMsg.str() << std::endl;
		throw BFDumpDotException(errorMsg.str());
		#else
		throw BFDumpDotException("MyDumpDot: Variable List was incomplete. Variable missing (unknown)");
		#endif
	}
		
	// Search for a suitable node
	for (unsigned int i=0;i<rc.nodes[level].size();i++) {
		MyDumpDotNode &current = rc.nodes[level][i];
		if ((current.getSuccF()==zeroBranch) && (current.getSuccT()==oneBranch))
			return std::pair<int,unsigned int>(level,i);
	}
	
	// Else: Make suitable node
	std::pair<int,unsigned int> continueZero = BDD_newDumpDotRecurse(zeroBranch, level+1, rc);
	std::pair<int,unsigned int> continueOne = BDD_newDumpDotRecurse(oneBranch, level+1, rc);
	rc.nodes[level].push_back(MyDumpDotNode(zeroBranch,oneBranch,continueZero.first,continueZero.second,continueOne.first,continueOne.second));
	rc.nodesSoFar++;
	return std::pair<int,unsigned int>(level,rc.nodes[level].size()-1);
}